All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.emul.java.util.Date Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * Copyright 2007 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package java.util;

import java.io.Serializable;

import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsType;

/**
 * Represents a date and time.
 */
public class Date implements Cloneable, Comparable, Serializable {

  /**
   * Encapsulates static data to avoid Date itself having a static initializer.
   */
  private static class StringData {
    public static final String[] DAYS = {
        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

    public static final String[] MONTHS = {
        "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
        "Nov", "Dec"};
  }

  public static long parse(String s) {
    double parsed = NativeDate.parse(s);
    if (Double.isNaN(parsed)) {
      throw new IllegalArgumentException();
    }
    return (long) parsed;
  }

  // CHECKSTYLE_OFF: Matching the spec.
  public static long UTC(int year, int month, int date, int hrs, int min,
      int sec) {
    return (long) NativeDate.UTC(year + 1900, month, date, hrs, min, sec, 0);
  }

  // CHECKSTYLE_ON

  /**
   * Ensure a number is displayed with two digits.
   *
   * @return a two-character base 10 representation of the number
   */
  protected static String padTwo(int number) {
    if (number < 10) {
      return "0" + number;
    } else {
      return String.valueOf(number);
    }
  }

  /**
   * JavaScript Date instance.
   */
  private final NativeDate jsdate;

  public Date() {
    jsdate = new NativeDate();
  }

  public Date(int year, int month, int date) {
    this(year, month, date, 0, 0, 0);
  }

  public Date(int year, int month, int date, int hrs, int min) {
    this(year, month, date, hrs, min, 0);
  }

  public Date(int year, int month, int date, int hrs, int min, int sec) {
    jsdate = new NativeDate();
    jsdate.setFullYear(year + 1900, month, date);
    jsdate.setHours(hrs, min, sec, 0);
    fixDaylightSavings(hrs);
  }

  public Date(long date) {
    jsdate = new NativeDate(date);
  }

  public Date(String date) {
    this(Date.parse(date));
  }

  public boolean after(Date when) {
    return getTime() > when.getTime();
  }

  public boolean before(Date when) {
    return getTime() < when.getTime();
  }

  public Object clone() {
    return new Date(getTime());
  }

  @Override
  public int compareTo(Date other) {
    return Long.compare(getTime(), other.getTime());
  }

  @Override
  public boolean equals(Object obj) {
    return ((obj instanceof Date) && (getTime() == ((Date) obj).getTime()));
  }

  public int getDate() {
    return jsdate.getDate();
  }

  public int getDay() {
    return jsdate.getDay();
  }

  public int getHours() {
    return jsdate.getHours();
  }

  public int getMinutes() {
    return jsdate.getMinutes();
  }

  public int getMonth() {
    return jsdate.getMonth();
  }

  public int getSeconds() {
    return jsdate.getSeconds();
  }

  public long getTime() {
    return (long) jsdate.getTime();
  }

  public int getTimezoneOffset() {
    return jsdate.getTimezoneOffset();
  }

  public int getYear() {
    return jsdate.getFullYear() - 1900;
  }

  @Override
  public int hashCode() {
    long time = getTime();
    return (int) (time ^ (time >>> 32));
  }

  public void setDate(int date) {
    int hours = jsdate.getHours();
    jsdate.setDate(date);
    fixDaylightSavings(hours);
  }

  public void setHours(int hours) {
    jsdate.setHours(hours);
    fixDaylightSavings(hours);
  }

  public void setMinutes(int minutes) {
    int hours = getHours() + minutes / 60;
    jsdate.setMinutes(minutes);
    fixDaylightSavings(hours);
  }

  public void setMonth(int month) {
    int hours = jsdate.getHours();
    jsdate.setMonth(month);
    fixDaylightSavings(hours);
  }

  public void setSeconds(int seconds) {
    int hours = getHours() + seconds / (60 * 60);
    jsdate.setSeconds(seconds);
    fixDaylightSavings(hours);
  }

  public void setTime(long time) {
    jsdate.setTime(time);
  }

  public void setYear(int year) {
    int hours = jsdate.getHours();
    jsdate.setFullYear(year + 1900);
    fixDaylightSavings(hours);
  }

  public String toGMTString() {
    return jsdate.getUTCDate() + " " + StringData.MONTHS[jsdate.getUTCMonth()]
        + " " + jsdate.getUTCFullYear() + " " + padTwo(jsdate.getUTCHours())
        + ":" + padTwo(jsdate.getUTCMinutes()) + ":"
        + padTwo(jsdate.getUTCSeconds()) + " GMT";
  }

  public String toLocaleString() {
    return jsdate.toLocaleString();
  }

  @Override
  public String toString() {
    // Compute timezone offset. The value that getTimezoneOffset returns is
    // backwards for the transformation that we want.
    int offset = -jsdate.getTimezoneOffset();
    String hourOffset = ((offset >= 0) ? "+" : "") + (offset / 60);
    String minuteOffset = padTwo(Math.abs(offset) % 60);

    return StringData.DAYS[jsdate.getDay()] + " "
        + StringData.MONTHS[jsdate.getMonth()] + " " + padTwo(jsdate.getDate())
        + " " + padTwo(jsdate.getHours()) + ":" + padTwo(jsdate.getMinutes())
        + ":" + padTwo(jsdate.getSeconds()) + " GMT" + hourOffset
        + minuteOffset + " " + jsdate.getFullYear();
  }

  private static final long ONE_HOUR_IN_MILLISECONDS = 60 * 60 * 1000;

  /*
   * Some browsers have the following behavior:
   *
   * GAP
   * // Assume a U.S. time zone with daylight savings
   * // Set a non-existent time: 2:00 am Sunday March 8, 2009
   * var date = new Date(2009, 2, 8, 2, 0, 0);
   * var hours = date.getHours(); // returns 1
   *
   * The equivalent Java code will return 3.
   *
   * OVERLAP
   * // Assume a U.S. time zone with daylight savings
   * // Set to an ambiguous time: 1:30 am Sunday November 1, 2009
   * var date = new Date(2009, 10, 1, 1, 30, 0);
   * var nextHour = new Date(date.getTime() + 60*60*1000);
   * var hours = nextHour.getHours(); // returns 1
   *
   * The equivalent Java code will return 2.
   *
   * To compensate, fixDaylightSavings adjusts the date to match Java semantics.
   */

  /**
   * Detects if the requested time falls into a non-existent time range due to local time advancing
   * into daylight savings time or is ambiguous due to going out of daylight savings. If so, adjust
   * accordingly.
   */
  private void fixDaylightSavings(int requestedHours) {
    requestedHours %= 24;
    if (jsdate.getHours() != requestedHours) {
      // Hours passed to the constructor don't match the hours in the created JavaScript Date; this
      // might be due either because they are outside 0-24 range, there was overflow from
      // minutes:secs:millis or because we are in the situation GAP and has to be fixed.
      NativeDate copy = new NativeDate(jsdate.getTime());
      copy.setDate(copy.getDate() + 1);
      int timeDiff = jsdate.getTimezoneOffset() - copy.getTimezoneOffset();

      // If the time zone offset is changing, advance the hours and
      // minutes from the initially requested time by the change amount
      if (timeDiff > 0) {
        // The requested time falls into a non-existent time range due to
        // local time advancing into daylight savings time. If so, push the requested
        // time forward out of the non-existent range.
        int timeDiffHours = timeDiff / 60;
        int timeDiffMinutes = timeDiff % 60;
        int day = jsdate.getDate();
        int badHours = jsdate.getHours();
        if (badHours + timeDiffHours >= 24) {
          day++;
        }
        NativeDate newTime = new NativeDate(jsdate.getFullYear(), jsdate.getMonth(),
            day, requestedHours + timeDiffHours, jsdate.getMinutes() + timeDiffMinutes,
            jsdate.getSeconds(), jsdate.getMilliseconds());
        jsdate.setTime(newTime.getTime());
      }
    }

    // Check for situation OVERLAP by advancing the clock by 1 hour and see if getHours() returns
    // the same. This solves issues like Safari returning '3/21/2015 23:00' when time is set to
    // '2/22/2015'.
    double originalTimeInMillis = jsdate.getTime();
    jsdate.setTime(originalTimeInMillis + ONE_HOUR_IN_MILLISECONDS);
    if (jsdate.getHours() != requestedHours) {
      // We are not in the duplicated hour, so revert the change.
      jsdate.setTime(originalTimeInMillis);
    }
  }

  @JsType(isNative = true, name = "Date", namespace = JsPackage.GLOBAL)
  private static class NativeDate {
    // CHECKSTYLE_OFF: Matching the spec.
    public static native double UTC(int year, int month, int dayOfMonth, int hours,
        int minutes, int seconds, int millis);
    // CHECKSTYLE_ON
    public static native double parse(String dateString);
    public NativeDate() { }
    public NativeDate(double milliseconds) { }
    public NativeDate(int year, int month, int dayOfMonth, int hours,
        int minutes, int seconds, int millis) { }
    public native int getDate();
    public native int getDay();
    public native int getFullYear();
    public native int getHours();
    public native int getMilliseconds();
    public native int getMinutes();
    public native int getMonth();
    public native int getSeconds();
    public native double getTime();
    public native int getTimezoneOffset();
    public native int getUTCDate();
    public native int getUTCFullYear();
    public native int getUTCHours();
    public native int getUTCMinutes();
    public native int getUTCMonth();
    public native int getUTCSeconds();
    public native void setDate(int dayOfMonth);
    public native void setFullYear(int year);
    public native void setFullYear(int year, int month, int day);
    public native void setHours(int hours);
    public native void setHours(int hours, int mins, int secs, int ms);
    public native void setMinutes(int minutes);
    public native void setMonth(int month);
    public native void setSeconds(int seconds);
    public native void setTime(double milliseconds);
    public native String toLocaleString();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy