view src/org/tmatesoft/hg/core/HgDate.java @ 366:189dc6dc1c3e

Use exceptions to expose errors reading mercurial data
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 16 Dec 2011 04:43:18 +0100
parents 4252faa556cd
children
line wrap: on
line source
/*
 * Copyright (c) 2011 TMate Software Ltd
 *  
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * For information on how to redistribute this software under
 * the terms of a license other than GNU General Public License
 * contact TMate Software at support@hg4j.com
 */
package org.tmatesoft.hg.core;

import java.util.Calendar;
import java.util.Formatter;
import java.util.Locale;
import java.util.TimeZone;

/**
 * Compound object to keep time  and time zone of a change. Time zone is not too useful unless you'd like to indicate where 
 * the change was made (original <em>hg</em> shows date of a change in its original time zone) 
 *
 * @author Artem Tikhomirov
 * @author TMate Software Ltd.
 */
public final class HgDate implements Comparable<HgDate>, Cloneable {
	private final long time;
	private final TimeZone tzone;
	

	/**
	 * @param millis UTC, milliseconds
	 * @param timezone zone offset in seconds, UTC - local == timezone. I.e. positive in the Western Hemisphere.  
	 */
	public HgDate(long millis, int timezone) {
		time = millis;
		// @see http://pydoc.org/2.5.1/time.html  time.timezone -- difference in seconds between UTC and local standard time
		// UTC - local = timezone. local = UTC - timezone
		// In Java, timezone is positive right of Greenwich, UTC+timezone = local
		//
		//
		/*
		 * The approach with available-short didn't work out as final timezone still relied
		 * on daylight saving settings (and added/substracted hour shift according to date supplied)
		 * E.g. 1218917104000 in zone GMT+2 (hello sample, changeset #2), results in EET timezone and 23 hours instead of 22
		 * 
		String[] available = TimeZone.getAvailableIDs(-timezone * 1000);
		assert available != null && available.length > 0 : String.valueOf(timezone);
		// this is sort of hack, I don't know another way how to get 
		// abbreviated name from zone offset (other than to have own mapping)
		// And I can't use any id, because e.g. zone with id  "US/Mountain" 
		// gives incorrect (according to hg cmdline) result, unlike MST or US/Arizona (all ids for zone -0700)
		// use 1125044450000L to see the difference
		String shortID = TimeZone.getTimeZone(available[0]).getDisplayName(false, TimeZone.SHORT);
		// XXX in fact, might need to handle daylight saving time, but not sure how, 
		// getTimeZone(GMT-timezone*1000).inDaylightTime()?
		TimeZone tz = TimeZone.getTimeZone(shortID);
		*/
		int tz_hours = -timezone/3600;
		int tz_mins = timezone % 3600;
		String customId = String.format("GMT%+02d:%02d", tz_hours, tz_mins);
		TimeZone tz = TimeZone.getTimeZone(customId);
		tzone = tz;
	}
	
	public long getRawTime() {
		return time;
	}
	
	/**
	 * @return zone object by reference, do not alter it (make own copy by {@link TimeZone#clone()}, to modify). 
	 */
	public TimeZone getTimeZone() {
		return tzone;
	}
	
	@Override
	public String toString() {
		// format the same way hg does
		return toString(Locale.US);
	}
	
	public String toString(Locale l) {
		Calendar c = Calendar.getInstance(getTimeZone());
		c.setTimeInMillis(getRawTime());
		Formatter f = new Formatter(new StringBuilder(), l);
		f.format("%ta %<tb %<td %<tH:%<tM:%<tS %<tY %<tz", c);
		return f.out().toString();
	}

	public int compareTo(HgDate o) {
		return (int) (time - o.time);
	}

	@Override
	public boolean equals(Object obj) {
		if (false == obj instanceof HgDate) {
			return false;
		}
		HgDate other = (HgDate) obj;
		return compareTo(other) == 0;
	}
	
	@Override
	public int hashCode() {
		// copied from java.util.Datge
		return (int) time ^ (int) (time >> 32);
	}

	@Override
	protected Object clone() {
		try {
			return super.clone();
		} catch (CloneNotSupportedException ex) {
			throw new InternalError(ex.toString());
		}
	}
}