view tango/tango/time/chrono/Hebrew.d @ 132:1700239cab2e trunk

[svn r136] MAJOR UNSTABLE UPDATE!!! Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
author lindquist
date Fri, 11 Jan 2008 17:57:40 +0100
parents
children
line wrap: on
line source

/*******************************************************************************

        copyright:      Copyright (c) 2005 John Chapman. All rights reserved

        license:        BSD style: $(LICENSE)

        version:        Mid 2005: Initial release
                        Apr 2007: reshaped                        

        author:         John Chapman, Kris, snoyberg

******************************************************************************/

module tango.time.chrono.Hebrew;

private import tango.core.Exception;

private import tango.time.chrono.Calendar;



/**
 * $(ANCHOR _Hebrew)
 * Represents the Hebrew calendar.
 */
public class Hebrew : Calendar {

  private const uint[14][7] MonthDays = [
    // month                                                    // year type
    [ 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0  ], 
    [ 0, 30, 29, 29, 29, 30, 29, 0,  30, 29, 30, 29, 30, 29 ],  // 1
    [ 0, 30, 29, 30, 29, 30, 29, 0,  30, 29, 30, 29, 30, 29 ],  // 2
    [ 0, 30, 30, 30, 29, 30, 29, 0,  30, 29, 30, 29, 30, 29 ],  // 3
    [ 0, 30, 29, 29, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29 ],  // 4
    [ 0, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29 ],  // 5
    [ 0, 30, 30, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29 ]   // 6
  ];

  private const uint YearOfOneAD = 3760;
  private const uint DaysToOneAD = cast(int)(YearOfOneAD * 365.2735);

  private const uint PartsPerHour = 1080;
  private const uint PartsPerDay = 24 * PartsPerHour;
  private const uint DaysPerMonth = 29;
  private const uint DaysPerMonthFraction = 12 * PartsPerHour + 793;
  private const uint PartsPerMonth = DaysPerMonth * PartsPerDay + DaysPerMonthFraction;
  private const uint FirstNewMoon = 11 * PartsPerHour + 204;

  private uint minYear_ = YearOfOneAD + 1583;
  private uint maxYear_ = YearOfOneAD + 2240;

  /**
   * Represents the current era.
   */
  public const uint HEBREW_ERA = 1;

  /**
   * Overridden. Returns a Time value set to the specified date and time in the specified _era.
   * Params:
   *   year = An integer representing the _year.
   *   month = An integer representing the _month.
   *   day = An integer representing the _day.
   *   hour = An integer representing the _hour.
   *   minute = An integer representing the _minute.
   *   second = An integer representing the _second.
   *   millisecond = An integer representing the _millisecond.
   *   era = An integer representing the _era.
   * Returns: A Time set to the specified date and time.
   */
  public override Time toTime(uint year, uint month, uint day, uint hour, uint minute, uint second, uint millisecond, uint era) {
    checkYear(year, era);
    return getGregorianTime(year, month, day, hour, minute, second, millisecond);
  }

  /**
   * Overridden. Returns the day of the week in the specified Time.
   * Params: time = A Time value.
   * Returns: A DayOfWeek value representing the day of the week of time.
   */
  public override DayOfWeek getDayOfWeek(Time time) {
    return cast(DayOfWeek) cast(uint) ((time.ticks / TimeSpan.TicksPerDay + 1) % 7);
  }

  /**
   * Overridden. Returns the day of the month in the specified Time.
   * Params: time = A Time value.
   * Returns: An integer representing the day of the month of time.
   */
  public override uint getDayOfMonth(Time time) {
    auto year = getYear(time);
    auto yearType = getYearType(year);
    auto days = getStartOfYear(year) - DaysToOneAD;
    auto day = cast(int)(time.ticks / TimeSpan.TicksPerDay) - days;
    uint n;
    while (n < 12 && day >= MonthDays[yearType][n + 1]) {
      day -= MonthDays[yearType][n + 1];
      n++;
    }
    return day + 1;
  }

  /**
   * Overridden. Returns the day of the year in the specified Time.
   * Params: time = A Time value.
   * Returns: An integer representing the day of the year of time.
   */
  public override uint getDayOfYear(Time time) {
    auto year = getYear(time);
    auto days = getStartOfYear(year) - DaysToOneAD;
    return (cast(uint)(time.ticks / TimeSpan.TicksPerDay) - days) + 1;
  }

  /**
   * Overridden. Returns the month in the specified Time.
   * Params: time = A Time value.
   * Returns: An integer representing the month in time.
   */
  public override uint getMonth(Time time) {
    auto year = getYear(time);
    auto yearType = getYearType(year);
    auto days = getStartOfYear(year) - DaysToOneAD;
    auto day = cast(int)(time.ticks / TimeSpan.TicksPerDay) - days;
    uint n;
    while (n < 12 && day >= MonthDays[yearType][n + 1]) {
      day -= MonthDays[yearType][n + 1];
      n++;
    }
    return n + 1;
  }

  /**
   * Overridden. Returns the year in the specified Time.
   * Params: time = A Time value.
   * Returns: An integer representing the year in time.
   */
  public override uint getYear(Time time) {
    auto day = cast(uint)(time.ticks / TimeSpan.TicksPerDay) + DaysToOneAD;
    auto low = minYear_, high = maxYear_;
    // Perform a binary search.
    while (low <= high) {
      auto mid = low + (high - low) / 2;
      auto startDay = getStartOfYear(mid);
      if (day < startDay)
        high = mid - 1;
      else if (day >= startDay && day < getStartOfYear(mid + 1))
        return mid;
      else
        low = mid + 1;
    }
    return low;
  }

  /**
   * Overridden. Returns the era in the specified Time.
   * Params: time = A Time value.
   * Returns: An integer representing the ear in time.
   */
  public override uint getEra(Time time) {
    return HEBREW_ERA;
  }

  /**
   * Overridden. Returns the number of days in the specified _year and _month of the specified _era.
   * Params:
   *   year = An integer representing the _year.
   *   month = An integer representing the _month.
   *   era = An integer representing the _era.
   * Returns: The number of days in the specified _year and _month of the specified _era.
   */
  public override uint getDaysInMonth(uint year, uint month, uint era) {
    checkYear(year, era);
    return MonthDays[getYearType(year)][month];
  }

  /**
   * Overridden. Returns the number of days in the specified _year of the specified _era.
   * Params:
   *   year = An integer representing the _year.
   *   era = An integer representing the _era.
   * Returns: The number of days in the specified _year in the specified _era.
   */
  public override uint getDaysInYear(uint year, uint era) {
    return getStartOfYear(year + 1) - getStartOfYear(year);
  }

  /**
   * Overridden. Returns the number of months in the specified _year of the specified _era.
   * Params:
   *   year = An integer representing the _year.
   *   era = An integer representing the _era.
   * Returns: The number of months in the specified _year in the specified _era.
   */
  public override uint getMonthsInYear(uint year, uint era) {
    return isLeapYear(year, era) ? 13 : 12;
  }

  /**
   * Overridden. Indicates whether the specified _year in the specified _era is a leap _year.
   * Params: year = An integer representing the _year.
   * Params: era = An integer representing the _era.
   * Returns: true is the specified _year is a leap _year; otherwise, false.
   */
  public override bool isLeapYear(uint year, uint era) {
    checkYear(year, era);
    // true if year % 19 == 0, 3, 6, 8, 11, 14, 17
    return ((7 * year + 1) % 19) < 7;
  }

  /**
   * $(I Property.) Overridden. Retrieves the list of eras in the current calendar.
   * Returns: An integer array representing the eras in the current calendar.
   */
  public override uint[] eras() {
        auto tmp = [HEBREW_ERA];
        return tmp.dup;
  }

  /**
   * $(I Property.) Overridden. Retrieves the identifier associated with the current calendar.
   * Returns: An integer representing the identifier of the current calendar.
   */
  public override uint id() {
    return HEBREW;
  }

  private void checkYear(uint year, uint era) {
    if ((era != CURRENT_ERA && era != HEBREW_ERA) || (year > maxYear_ || year < minYear_))
      throw new IllegalArgumentException("Value was out of range.");
  }

  private uint getYearType(uint year) {
    int yearLength = getStartOfYear(year + 1) - getStartOfYear(year);
    if (yearLength > 380)
      yearLength -= 30;
    switch (yearLength) {
      case 353:
        // "deficient"
        return 1;
      case 383:
        // "deficient" leap
        return 4;
      case 354:
        // "normal"
        return 2;
      case 384:
        // "normal" leap
        return 5;
      case 355:
        // "complete"
        return 3;
      case 385:
        // "complete" leap
        return 6;
      default:
        break;
    }
    // Satisfies -w
    throw new IllegalArgumentException("Value was not valid.");
  }

  private uint getStartOfYear(uint year) {
    auto months = (235 * year - 234) / 19;
    auto fraction = months * DaysPerMonthFraction + FirstNewMoon;
    auto day = months * 29 + (fraction / PartsPerDay);
    fraction %= PartsPerDay;

    auto dayOfWeek = day % 7;
    if (dayOfWeek == 2 || dayOfWeek == 4 || dayOfWeek == 6) {
      day++;
      dayOfWeek = day % 7;
    }
    if (dayOfWeek == 1 && fraction > 15 * PartsPerHour + 204 && !isLeapYear(year, CURRENT_ERA))
      day += 2;
    else if (dayOfWeek == 0 && fraction > 21 * PartsPerHour + 589 && isLeapYear(year, CURRENT_ERA))
      day++;
    return day;
  }

  private Time getGregorianTime(uint year, uint month, uint day, uint hour, uint minute, uint second, uint millisecond) {
    auto yearType = getYearType(year);
    auto days = getStartOfYear(year) - DaysToOneAD + day - 1;
    for (int i = 1; i <= month; i++)
      days += MonthDays[yearType][i - 1];
    return Time((days * TimeSpan.TicksPerDay) + getTimeTicks(hour, minute, second)) + TimeSpan.millis(millisecond);
  }

}