/* * Copyright 2017 dmfs GmbH * * 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 org.dmfs.tasks.model.adapters; import java.util.Date; import java.util.TimeZone; /** * This is a wrapper for a {@link TimeZone} that provides a less strict {@link #equals(Object)} method than some {@link TimeZone} implementations. * * @author Marten Gajda <[email protected]> */ public class TimeZoneWrapper extends TimeZone { /** * Generated serial id. */ private static final long serialVersionUID = -7166830450275216013L; /** * Time stamp of 2013-01-01 00:00:00 UTC. */ private final static Date TEST_DATE = new Date(1356998400000L); /** * The {@link TimeZone} this instance wraps. */ private final TimeZone mTimeZone; private Long mReferenceTimeStamp; /** * Constructor that wraps the default time zone. */ public TimeZoneWrapper() { mTimeZone = TimeZone.getDefault(); setID(mTimeZone.getID()); } /** * Constructor that wraps the given {@link TimeZone}. * * @param timeZone * The {@link TimeZone} to wrap. */ public TimeZoneWrapper(TimeZone timeZone) { mTimeZone = timeZone; setID(timeZone.getID()); } /** * Constructor that wraps the time zone with the given ID. * * @param id * The time zone id of the time zone to wrap. */ public TimeZoneWrapper(String id) { mTimeZone = TimeZone.getTimeZone(id); setID(mTimeZone.getID()); } @Override public int getOffset(int era, int year, int month, int day, int dayOfWeek, int timeOfDayMillis) { return mTimeZone.getOffset(era, year, month, day, dayOfWeek, timeOfDayMillis); } @Override public int getRawOffset() { return mTimeZone.getRawOffset(); } @Override public boolean inDaylightTime(Date time) { return mTimeZone.inDaylightTime(time); } @Override public void setRawOffset(int offsetMillis) { mTimeZone.setRawOffset(offsetMillis); } @Override public boolean useDaylightTime() { return mTimeZone.useDaylightTime(); } public void setReferenceTimeStamp(Long timeStamp) { mReferenceTimeStamp = timeStamp; } public Long getReferenceTimeStamp() { return mReferenceTimeStamp; } public int getReferenceTimeOffset() { if (mReferenceTimeStamp != null) { return mTimeZone.getOffset(mReferenceTimeStamp); } else { return mTimeZone.getRawOffset(); } } public int getOffset(Long timestamp) { if (timestamp != null) { return mTimeZone.getOffset(timestamp); } else { return mTimeZone.getRawOffset(); } } public boolean referenceInDaylightTime() { if (mReferenceTimeStamp != null) { return mTimeZone.inDaylightTime(new Date(mReferenceTimeStamp)); } else { return false; } } public boolean inDaylightTime(Long timestamp) { if (timestamp != null) { return mTimeZone.inDaylightTime(new Date(timestamp)); } else { return false; } } @Override public int hashCode() { /* * Return the raw offset as hash code. It satisfies the requirements of a hash values: Time zones that are equal have the same raw offset. */ return getRawOffset(); } @Override public boolean equals(Object object) { if (!(object instanceof TimeZoneWrapper)) // matches null too { return false; } TimeZone otherTimeZone = (TimeZone) object; /* * This is a very simple check for equality of two time zones. It returns the wrong result if two time zones have the same UTC offset, but use different * dates to switch to summer time. * * Are there such cases? How can we improve it? Maybe by testing a few more days in March and October? * * TODO: improve the check */ return (mTimeZone.getID().equals(otherTimeZone.getID())) || (mTimeZone.useDaylightTime() == otherTimeZone.useDaylightTime() && mTimeZone.getRawOffset() == otherTimeZone.getRawOffset() && mTimeZone.getDSTSavings() == otherTimeZone.getDSTSavings() && mTimeZone.inDaylightTime(TEST_DATE) == otherTimeZone.inDaylightTime( TEST_DATE)); } @Override public String toString() { return mTimeZone.toString(); } }