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; }