private DateTime(long ticks, TimeZone tz)
{
// check boundary conditions 1901 to 2099
if (ticks < minTicks || ticks >= maxTicks)
{
throw ArgErr.make("Ticks out of range 1901 to 2099").val;
}
// save ticks, time zone
this.m_ticks = ticks;
this.m_tz = tz;
// compute the year
int year = ticksToYear(ticks);
// get the time zone rule for this year, and
// offset the working ticks by UTC offset
TimeZone.Rule rule = m_tz.rule(year);
ticks += rule.offset * nsPerSec;
// compute the day and month; we may need to execute this
// code block up to three times:
// 1st: using standard time
// 2nd: using daylight offset (if in dst)
// 3rd: using standard time (if dst pushed us back into std)
int month, day, dstOffset = 0;
long rem;
while (true)
{
// recompute year based on working ticks
year = ticksToYear(ticks);
rem = ticks - yearTicks[year - 1900];
if (rem < 0)
{
rem += nsPerYear;
}
// compute day of the year
int dayOfYear = (int)(rem / nsPerDay);
rem %= nsPerDay;
// use lookup tables map day of year to month and day
if (isLeapYear(year))
{
month = monForDayOfYearLeap[dayOfYear];
day = dayForDayOfYearLeap[dayOfYear];
}
else
{
month = monForDayOfYear[dayOfYear];
day = dayForDayOfYear[dayOfYear];
}
// if dstOffset is set to max, then this is
// the third time thru the loop: std->dst->std
if (dstOffset == System.Int32.MaxValue)
{
dstOffset = 0; break;
}
// if dstOffset is non-zero we have run this
// loop twice to recompute the date for dst
if (dstOffset != 0)
{
// if our dst rule is wall time based, then we need to
// recompute to see if dst wall time pushed us back
// into dst - if so then run through the loop a third
// time to get us back to standard time
if (rule.isWallTime() && TimeZone.dstOffset(rule, year, month, day, (int)(rem / nsPerSec)) == 0)
{
ticks -= dstOffset * nsPerSec;
dstOffset = System.Int32.MaxValue;
continue;
}
break;
}
// first time in loop; check for daylight saving time,
// and if dst is in effect then re-run this loop with
// modified working ticks
dstOffset = TimeZone.dstOffset(rule, year, month, day, (int)(rem / nsPerSec));
if (dstOffset == 0)
{
break;
}
ticks += dstOffset * nsPerSec;
}
// compute time of day
int hour = (int)(rem / nsPerHour); rem %= nsPerHour;
int min = (int)(rem / nsPerMin); rem %= nsPerMin;
// compute weekday
int weekday = (firstWeekday(year, month) + day - 1) % 7;
// fields
int fields = 0;
fields |= ((year - 1900) & 0xff) << 0;
fields |= (month & 0xf) << 8;
fields |= (day & 0x1f) << 12;
fields |= (hour & 0x1f) << 17;
fields |= (min & 0x3f) << 22;
fields |= (weekday & 0x7) << 28;
fields |= (dstOffset != 0 ? 1 : 0) << 31;
this.m_fields = fields;
}