tikhomirov@211: /*
tikhomirov@211: * Copyright (c) 2011 TMate Software Ltd
tikhomirov@211: *
tikhomirov@211: * This program is free software; you can redistribute it and/or modify
tikhomirov@211: * it under the terms of the GNU General Public License as published by
tikhomirov@211: * the Free Software Foundation; version 2 of the License.
tikhomirov@211: *
tikhomirov@211: * This program is distributed in the hope that it will be useful,
tikhomirov@211: * but WITHOUT ANY WARRANTY; without even the implied warranty of
tikhomirov@211: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
tikhomirov@211: * GNU General Public License for more details.
tikhomirov@211: *
tikhomirov@211: * For information on how to redistribute this software under
tikhomirov@211: * the terms of a license other than GNU General Public License
tikhomirov@211: * contact TMate Software at support@hg4j.com
tikhomirov@211: */
tikhomirov@211: package org.tmatesoft.hg.core;
tikhomirov@211:
tikhomirov@211: import java.util.Calendar;
tikhomirov@211: import java.util.Formatter;
tikhomirov@211: import java.util.Locale;
tikhomirov@211: import java.util.TimeZone;
tikhomirov@211:
tikhomirov@211: /**
tikhomirov@211: * Compound object to keep time and time zone of a change. Time zone is not too useful unless you'd like to indicate where
tikhomirov@211: * the change was made (original hg shows date of a change in its original time zone)
tikhomirov@211: *
tikhomirov@211: * @author Artem Tikhomirov
tikhomirov@211: * @author TMate Software Ltd.
tikhomirov@211: */
tikhomirov@211: public final class HgDate implements Comparable, Cloneable {
tikhomirov@211: private final long time;
tikhomirov@211: private final TimeZone tzone;
tikhomirov@211:
tikhomirov@211:
tikhomirov@211: /**
tikhomirov@211: * @param millis UTC, milliseconds
tikhomirov@211: * @param timezone zone offset in seconds, UTC - local == timezone. I.e. positive in the Western Hemisphere.
tikhomirov@211: */
tikhomirov@211: public HgDate(long millis, int timezone) {
tikhomirov@211: time = millis;
tikhomirov@211: // @see http://pydoc.org/2.5.1/time.html time.timezone -- difference in seconds between UTC and local standard time
tikhomirov@211: // UTC - local = timezone. local = UTC - timezone
tikhomirov@211: // In Java, timezone is positive right of Greenwich, UTC+timezone = local
tikhomirov@214: //
tikhomirov@214: //
tikhomirov@214: /*
tikhomirov@214: * The approach with available-short didn't work out as final timezone still relied
tikhomirov@214: * on daylight saving settings (and added/substracted hour shift according to date supplied)
tikhomirov@214: * E.g. 1218917104000 in zone GMT+2 (hello sample, changeset #2), results in EET timezone and 23 hours instead of 22
tikhomirov@214: *
tikhomirov@211: String[] available = TimeZone.getAvailableIDs(-timezone * 1000);
tikhomirov@211: assert available != null && available.length > 0 : String.valueOf(timezone);
tikhomirov@214: // this is sort of hack, I don't know another way how to get
tikhomirov@211: // abbreviated name from zone offset (other than to have own mapping)
tikhomirov@211: // And I can't use any id, because e.g. zone with id "US/Mountain"
tikhomirov@211: // gives incorrect (according to hg cmdline) result, unlike MST or US/Arizona (all ids for zone -0700)
tikhomirov@211: // use 1125044450000L to see the difference
tikhomirov@211: String shortID = TimeZone.getTimeZone(available[0]).getDisplayName(false, TimeZone.SHORT);
tikhomirov@211: // XXX in fact, might need to handle daylight saving time, but not sure how,
tikhomirov@211: // getTimeZone(GMT-timezone*1000).inDaylightTime()?
tikhomirov@211: TimeZone tz = TimeZone.getTimeZone(shortID);
tikhomirov@214: */
tikhomirov@214: int tz_hours = -timezone/3600;
tikhomirov@214: int tz_mins = timezone % 3600;
tikhomirov@214: String customId = String.format("GMT%+02d:%02d", tz_hours, tz_mins);
tikhomirov@214: TimeZone tz = TimeZone.getTimeZone(customId);
tikhomirov@211: tzone = tz;
tikhomirov@211: }
tikhomirov@211:
tikhomirov@211: public long getRawTime() {
tikhomirov@211: return time;
tikhomirov@211: }
tikhomirov@211:
tikhomirov@211: /**
tikhomirov@211: * @return zone object by reference, do not alter it (make own copy by {@link TimeZone#clone()}, to modify).
tikhomirov@211: */
tikhomirov@211: public TimeZone getTimeZone() {
tikhomirov@211: return tzone;
tikhomirov@211: }
tikhomirov@211:
tikhomirov@211: @Override
tikhomirov@211: public String toString() {
tikhomirov@211: // format the same way hg does
tikhomirov@211: return toString(Locale.US);
tikhomirov@211: }
tikhomirov@211:
tikhomirov@211: public String toString(Locale l) {
tikhomirov@211: Calendar c = Calendar.getInstance(getTimeZone());
tikhomirov@211: c.setTimeInMillis(getRawTime());
tikhomirov@211: Formatter f = new Formatter(new StringBuilder(), l);
tikhomirov@211: f.format("%ta %> 32);
tikhomirov@211: }
tikhomirov@211:
tikhomirov@211: @Override
tikhomirov@211: protected Object clone() {
tikhomirov@211: try {
tikhomirov@211: return super.clone();
tikhomirov@211: } catch (CloneNotSupportedException ex) {
tikhomirov@211: throw new InternalError(ex.toString());
tikhomirov@211: }
tikhomirov@211: }
tikhomirov@211: }