/**
   * Return a new dateTime with the same normalized value, but in a different timezone.
   *
   * @param timezone the new timezone offset, in minutes
   * @return the date/time in the new timezone. This will be a new DateTimeValue unless no change
   *     was required to the original value
   */
  public CalendarValue adjustTimezone(int timezone) {
    if (!hasTimezone()) {
      CalendarValue in = (CalendarValue) copyAsSubType(typeLabel);
      in.setTimezoneInMinutes(timezone);
      return in;
    }
    int oldtz = getTimezoneInMinutes();
    if (oldtz == timezone) {
      return this;
    }
    int tz = timezone - oldtz;
    int h = hour;
    int mi = minute;
    mi += tz;
    if (mi < 0 || mi > 59) {
      h += Math.floor(mi / 60.0);
      mi = (mi + 60 * 24) % 60;
    }

    if (h >= 0 && h < 24) {
      return new DateTimeValue(
          year, month, day, (byte) h, (byte) mi, second, microsecond, timezone);
    }

    // Following code is designed to handle the corner case of adjusting from -14:00 to +14:00 or
    // vice versa, which can cause a change of two days in the date
    DateTimeValue dt = this;
    while (h < 0) {
      h += 24;
      DateValue t = DateValue.yesterday(dt.getYear(), dt.getMonth(), dt.getDay());
      dt =
          new DateTimeValue(
              t.getYear(),
              t.getMonth(),
              t.getDay(),
              (byte) h,
              (byte) mi,
              second,
              microsecond,
              timezone);
    }
    if (h > 23) {
      h -= 24;
      DateValue t = DateValue.tomorrow(year, month, day);
      return new DateTimeValue(
          t.getYear(),
          t.getMonth(),
          t.getDay(),
          (byte) h,
          (byte) mi,
          second,
          microsecond,
          timezone);
    }
    return dt;
  }
 static int hashCode(
     int year,
     byte month,
     byte day,
     byte hour,
     byte minute,
     byte second,
     int microsecond,
     int tzMinutes) {
   int tz = -tzMinutes;
   int h = hour;
   int mi = minute;
   mi += tz;
   if (mi < 0 || mi > 59) {
     h += Math.floor(mi / 60.0);
     mi = (mi + 60 * 24) % 60;
   }
   while (h < 0) {
     h += 24;
     DateValue t = DateValue.yesterday(year, month, day);
     year = t.getYear();
     month = t.getMonth();
     day = t.getDay();
   }
   while (h > 23) {
     h -= 24;
     DateValue t = DateValue.tomorrow(year, month, day);
     year = t.getYear();
     month = t.getMonth();
     day = t.getDay();
   }
   return (year << 4)
       ^ (month << 28)
       ^ (day << 23)
       ^ (h << 18)
       ^ (mi << 13)
       ^ second
       ^ microsecond;
 }