Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / search / DateUtil.java
blob5146afb02fb226d344bf7b587d0edd3e53397a31
1 // Copyright 2012 Google Inc. All Rights Reserved.
3 package com.google.appengine.api.search;
5 import com.google.apphosting.api.AppEngineInternal;
7 import java.text.DateFormat;
8 import java.text.ParsePosition;
9 import java.text.SimpleDateFormat;
10 import java.util.Calendar;
11 import java.util.Date;
12 import java.util.GregorianCalendar;
13 import java.util.Locale;
14 import java.util.TimeZone;
16 /**
17 * A utility class that centralizes processing of dates.
20 @AppEngineInternal
21 public final class DateUtil {
23 /**
24 * The milliseconds in a day.
26 public static final int MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
28 /**
29 * The UTC time zone.
31 private static final ThreadLocal<TimeZone> UTC_TZ =
32 new ThreadLocal<TimeZone>() {
33 @Override protected TimeZone initialValue() {
34 return TimeZone.getTimeZone("UTC");
38 private static DateFormat getDateFormat(String formatString) {
39 DateFormat format = new SimpleDateFormat(formatString, Locale.US);
40 format.setTimeZone(UTC_TZ.get());
41 return format;
44 private static final ThreadLocal<DateFormat> ISO8601_SIMPLE =
45 new ThreadLocal<DateFormat>() {
46 @Override protected DateFormat initialValue() {
47 return getDateFormat("yyyy-MM-dd");
51 private static final ThreadLocal<DateFormat> ISO8601_DATE_TIME_SIMPLE =
52 new ThreadLocal<DateFormat>() {
53 @Override protected DateFormat initialValue() {
54 return getDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
58 private static final ThreadLocal<DateFormat> ISO8601_DATE_TIME_SIMPLE_ERA =
59 new ThreadLocal<DateFormat>() {
60 @Override protected DateFormat initialValue() {
61 return getDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'G");
65 private DateUtil() {
68 /**
69 * Get a UTC calendar with Locale US.
71 private static Calendar getCalendarUTC() {
72 return new GregorianCalendar(UTC_TZ.get(), Locale.US);
75 /**
76 * Formats a date according ISO 8601 full date time format. Currently,
77 * this is used to print dates for error messages.
79 * @param date the date to format as a string
80 * @return a string representing the date in ISO 8601 format
82 public static String formatDateTime(Date date) {
83 if (date == null) {
84 return null;
86 return isBeforeCommonEra(date) ?
87 ISO8601_DATE_TIME_SIMPLE_ERA.get().format(date) :
88 ISO8601_DATE_TIME_SIMPLE.get().format(date);
91 /**
92 * Returns true if the date is before the common era.
94 private static boolean isBeforeCommonEra(Date date) {
95 Calendar cal = getCalendarUTC();
96 cal.setTime(date);
97 return cal.get(Calendar.ERA) == GregorianCalendar.BC;
101 * Parses an ISO 8601 into a {@link Date} object.
103 * This function is only used for deserializing legacy "yyyy-MM-dd"
104 * formatted dates stored in backend. These are currently not supporting
105 * BC Era dates, so neither will this function.
107 * @param dateString the ISO 8601 formatted string for a date
108 * @return the {@link Date} parsed from the date string
110 private static Date parseDate(String dateString) {
111 ParsePosition pos = new ParsePosition(0);
112 Date d = ISO8601_SIMPLE.get().parse(dateString, pos);
113 if (pos.getIndex() < dateString.length()) {
114 throw new IllegalArgumentException(
115 String.format("Failed to parse date string \"%s\"", dateString));
117 return d;
121 * Converts date into a string containing the milliseconds since the UNIX Epoch.
123 * @param date the date to serialize as a string
124 * @return a string representing the date as milliseconds since the UNIX Epoch
126 public static String serializeDate(Date date) {
127 return date == null ? "" : Long.toString(date.getTime());
131 * Converts a string containing the milliseconds since the UNIX Epoch into a Date.
133 * Two formats of date string are supported: "yyyy-MM-dd" and a long. Eventually,
134 * the "yyyy-MM-dd" format support will be removed.
136 * @param date the date string to deserialize into a date
137 * @return a date
139 public static Date deserializeDate(String date) {
140 if (date == null) {
141 return null;
143 if (date.startsWith("-")) {
144 if (date.length() > 1 && date.indexOf('-', 1) >= 0) {
145 return parseDate(date);
147 } else {
148 if (date.indexOf('-') > 0) {
149 return parseDate(date);
152 return new Date(Long.parseLong(date));
156 * Constructs a {@link Date} set to the UNIX Epoch plus days plus milliseconds.
158 * @param days the number of days to add to the UNIX Epoch to
159 * get a Date
160 * @param milliseconds the number of milliseconds to add to the date
161 * @return the Date with number of days plus Epoch
163 public static final Date getEpochPlusDays(int days, int milliseconds) {
164 Calendar cal = getCalendarUTC();
165 cal.setTimeInMillis(0L);
166 cal.add(Calendar.DATE, days);
167 cal.add(Calendar.MILLISECOND, milliseconds);
168 return cal.getTime();