Immutable representation of a date with an optional time and an optional time zone based on RFC 3339. : Mutable « Data Type « Java






Immutable representation of a date with an optional time and an optional time zone based on RFC 3339.

    
/*
 * Copyright (c) 2010 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 com.google.api.client.util;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

/**
 * Immutable representation of a date with an optional time and an optional time zone based on RFC
 * 3339.
 *
 * @since 1.0
 * @author Yaniv Inbar
 */
public class DateTime {

  private static final TimeZone GMT = TimeZone.getTimeZone("GMT");

  /**
   * Date/time value expressed as the number of ms since the Unix epoch.
   *
   *  If the time zone is specified, this value is normalized to UTC, so to format this date/time
   * value, the time zone shift has to be applied.
   */
  public final long value;

  /** Specifies whether this is a date-only value. */
  public final boolean dateOnly;

  /**
   * Time zone shift from UTC in minutes. If {@code null}, no time zone is set, and the time is
   * always interpreted as local time.
   */
  public final Integer tzShift;

  public DateTime(Date date, TimeZone zone) {
    long value = date.getTime();
    dateOnly = false;
    this.value = value;
    tzShift = zone.getOffset(value) / 60000;
  }

  public DateTime(long value) {
    this(false, value, null);
  }

  public DateTime(Date value) {
    this(value.getTime());
  }

  public DateTime(long value, Integer tzShift) {
    this(false, value, tzShift);
  }

  public DateTime(boolean dateOnly, long value, Integer tzShift) {
    this.dateOnly = dateOnly;
    this.value = value;
    this.tzShift = tzShift;
  }

  /** Formats the value as an RFC 3339 date/time string. */
  public String toStringRfc3339() {

    StringBuilder sb = new StringBuilder();

    Calendar dateTime = new GregorianCalendar(GMT);
    long localTime = value;
    Integer tzShift = this.tzShift;
    if (tzShift != null) {
      localTime += tzShift.longValue() * 60000;
    }
    dateTime.setTimeInMillis(localTime);

    appendInt(sb, dateTime.get(Calendar.YEAR), 4);
    sb.append('-');
    appendInt(sb, dateTime.get(Calendar.MONTH) + 1, 2);
    sb.append('-');
    appendInt(sb, dateTime.get(Calendar.DAY_OF_MONTH), 2);

    if (!dateOnly) {

      sb.append('T');
      appendInt(sb, dateTime.get(Calendar.HOUR_OF_DAY), 2);
      sb.append(':');
      appendInt(sb, dateTime.get(Calendar.MINUTE), 2);
      sb.append(':');
      appendInt(sb, dateTime.get(Calendar.SECOND), 2);

      if (dateTime.isSet(Calendar.MILLISECOND)) {
        sb.append('.');
        appendInt(sb, dateTime.get(Calendar.MILLISECOND), 3);
      }
    }

    if (tzShift != null) {

      if (tzShift.intValue() == 0) {

        sb.append('Z');

      } else {

        int absTzShift = tzShift.intValue();
        if (tzShift > 0) {
          sb.append('+');
        } else {
          sb.append('-');
          absTzShift = -absTzShift;
        }

        int tzHours = absTzShift / 60;
        int tzMinutes = absTzShift % 60;
        appendInt(sb, tzHours, 2);
        sb.append(':');
        appendInt(sb, tzMinutes, 2);
      }
    }

    return sb.toString();
  }

  @Override
  public String toString() {
    return toStringRfc3339();
  }

  @Override
  public boolean equals(Object o) {
    if (o == this) {
      return true;
    }
    if (!(o instanceof DateTime)) {
      return false;
    }
    DateTime other = (DateTime) o;
    return dateOnly == other.dateOnly && value == other.value;
  }

  /**
   * Parses an RFC 3339 date/time value.
   */
  public static DateTime parseRfc3339(String str) throws NumberFormatException {
    try {
      Calendar dateTime = new GregorianCalendar(GMT);
      int year = Integer.parseInt(str.substring(0, 4));
      int month = Integer.parseInt(str.substring(5, 7)) - 1;
      int day = Integer.parseInt(str.substring(8, 10));
      int tzIndex;
      int length = str.length();
      boolean dateOnly = length <= 10 || Character.toUpperCase(str.charAt(10)) != 'T';
      if (dateOnly) {
        dateTime.set(year, month, day);
        tzIndex = 10;
      } else {
        int hourOfDay = Integer.parseInt(str.substring(11, 13));
        int minute = Integer.parseInt(str.substring(14, 16));
        int second = Integer.parseInt(str.substring(17, 19));
        dateTime.set(year, month, day, hourOfDay, minute, second);
        if (str.charAt(19) == '.') {
          int milliseconds = Integer.parseInt(str.substring(20, 23));
          dateTime.set(Calendar.MILLISECOND, milliseconds);
          tzIndex = 23;
        } else {
          tzIndex = 19;
        }
      }
      Integer tzShiftInteger = null;
      long value = dateTime.getTimeInMillis();
      if (length > tzIndex) {
        int tzShift;
        if (Character.toUpperCase(str.charAt(tzIndex)) == 'Z') {
          tzShift = 0;
        } else {
          tzShift = Integer.parseInt(str.substring(tzIndex + 1, tzIndex + 3)) * 60
              + Integer.parseInt(str.substring(tzIndex + 4, tzIndex + 6));
          if (str.charAt(tzIndex) == '-') {
            tzShift = -tzShift;
          }
          value -= tzShift * 60000;
        }
        tzShiftInteger = tzShift;
      }
      return new DateTime(dateOnly, value, tzShiftInteger);
    } catch (StringIndexOutOfBoundsException e) {
      throw new NumberFormatException("Invalid date/time format.");
    }
  }

  /** Appends a zero-padded number to a string builder. */
  private static void appendInt(StringBuilder sb, int num, int numDigits) {
    if (num < 0) {
      sb.append('-');
      num = -num;
    }
    int x = num;
    while (x > 0) {
      x /= 10;
      numDigits--;
    }
    for (int i = 0; i < numDigits; i++) {
      sb.append('0');
    }
    if (num != 0) {
      sb.append(num);
    }
  }
}

   
    
    
    
  








Related examples in the same category

1.Mutable IntegerMutable Integer
2.Mutable double
3.Immutable Bit
4.Mutable Boolean
5.Mutable Int
6.Mutable Long
7.A reassignable integer usable for counting.