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

com.google.ical.compat.jodatime.TimeZoneConverter Maven / Gradle / Ivy

The newest version!
// Copyright (C) 2006 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.ical.compat.jodatime;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

/**
 * Replacement for Joda-time's broken {@link DateTimeZone#toTimeZone} which
 * returns a java.util.TimeZone that supposedly is equivalent to
 * the DateTimeZone.
 * Joda time's implementation simply uses the ID to look up the corresponding
 * java.util.TimeZones which should not be used since they're
 * frequently out-of-date re Brazilian timezones.
 *
 * 

See Sun bug 4328058. * * @author [email protected] (Mike Samuel) */ final class TimeZoneConverter { static final int MILLISECONDS_PER_SECOND = 1000; static final int MILLISECONDS_PER_MINUTE = 60 * MILLISECONDS_PER_SECOND; static final int MILLISECONDS_PER_HOUR = 60 * MILLISECONDS_PER_MINUTE; private static final Pattern HOUR_MINUTE = Pattern.compile( "^[+-]?[0-9]{1,2}:[0-9]{2}(:[0-9]{2})?$"); private static final TimeZone UTC = new SimpleTimeZone(0, "UTC"); private static final long MILLIS_SINCE_1_JAN_2000_UTC; static { GregorianCalendar c = new GregorianCalendar(UTC); c.set(2000, 0, 1, 0, 0, 0); MILLIS_SINCE_1_JAN_2000_UTC = c.getTimeInMillis(); } /** * return a java.util.Timezone object that delegates to * the given Joda DateTimeZone. */ public static TimeZone toTimeZone(final DateTimeZone dtz) { TimeZone tz = new TimeZone() { @Override public void setRawOffset(int n) { throw new UnsupportedOperationException(); } @Override public boolean useDaylightTime() { long firstTransition = MILLIS_SINCE_1_JAN_2000_UTC; return firstTransition != dtz.nextTransition(firstTransition); } @Override public boolean inDaylightTime(Date d) { long t = d.getTime(); return dtz.getStandardOffset(t) != dtz.getOffset(t); } @Override public int getRawOffset() { return dtz.getStandardOffset(0); } @Override public int getOffset(long instant) { // This method is not abstract, but it normally calls through to the // method below. // It's optimized here since there's a direct equivalent in // DateTimeZone. // DateTimeZone and java.util.TimeZone use the same // epoch so there's no translation of instant required. return dtz.getOffset(instant); } @Override public int getOffset( int era, int year, int month, int day, int dayOfWeek, int milliseconds) { int millis = milliseconds; // milliseconds is day in standard time int hour = millis / MILLISECONDS_PER_HOUR; millis %= MILLISECONDS_PER_HOUR; int minute = millis / MILLISECONDS_PER_MINUTE; millis %= MILLISECONDS_PER_MINUTE; int second = millis / MILLISECONDS_PER_SECOND; millis %= MILLISECONDS_PER_SECOND; if (era == GregorianCalendar.BC) { year = -(year - 1); } // get the time in UTC in case a timezone has changed it's standard // offset, e.g. rid of a half hour from UTC. DateTime dt = null; try { dt = new DateTime(year, month + 1, day, hour, minute, second, millis, dtz); } catch (IllegalArgumentException ex) { // Java does not complain if you try to convert a Date that does not // exist due to the offset shifting forward, but Joda time does. // Since we're trying to preserve the semantics of TimeZone, shift // forward over the gap so that we're on a time that exists. // This assumes that the DST correction is one hour long or less. if (hour < 23) { dt = new DateTime(year, month + 1, day, hour + 1, minute, second, millis, dtz); } else { // Some timezones shift at midnight. Calendar c = new GregorianCalendar(); c.clear(); c.setTimeZone(TimeZone.getTimeZone("UTC")); c.set(year, month, day, hour, minute, second); c.add(Calendar.HOUR_OF_DAY, 1); int year2 = c.get(Calendar.YEAR), month2 = c.get(Calendar.MONTH), day2 = c.get(Calendar.DAY_OF_MONTH), hour2 = c.get(Calendar.HOUR_OF_DAY); dt = new DateTime(year2, month2 + 1, day2, hour2, minute, second, millis, dtz); } } // since millis is in standard time, we construct the equivalent // GMT+xyz timezone and use that to convert. int offset = dtz.getStandardOffset(dt.getMillis()); DateTime stdDt = new DateTime( year, month + 1, day, hour, minute, second, millis, DateTimeZone.forOffsetMillis(offset)); return getOffset(stdDt.getMillis()); } @Override public String toString() { return dtz.toString(); } @Override public boolean equals(Object that) { if (!(that instanceof TimeZone)) { return false; } TimeZone thatTz = (TimeZone) that; return getID().equals(thatTz.getID()) && hasSameRules(thatTz); } @Override public int hashCode() { return getID().hashCode(); } private static final long serialVersionUID = 58752546800455L; }; // Now fix the tzids. DateTimeZone has a bad habit of returning // "+06:00" when it should be "GMT+06:00" String newTzid = cleanUpTzid(dtz.getID()); tz.setID(newTzid); return tz; } /** * If tzid is of the form [+-]hh:mm, we rewrite it to GMT[+-]hh:mm * Otherwise return it unchanged. */ static String cleanUpTzid(String tzid) { Matcher m = HOUR_MINUTE.matcher(tzid); return m.matches() ? // of the form [+-]hh:mm "GMT" + (tzid.startsWith("-") || tzid.startsWith("+") ? "" : "+") + tzid : tzid; } private TimeZoneConverter() { // uninstantiable } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy