Time difference - strange result - java

I have very simple code which calculates difference between two times:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
public class JavaApplication8 {
private static final SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mm:ss.SSS");
public static void main(String[] args) throws InterruptedException {
Date start = GregorianCalendar.getInstance().getTime();
Thread.sleep(100);
Date end = GregorianCalendar.getInstance().getTime();
long diff = end.getTime() - start.getTime();
System.out.println(timeFormat.format(diff));
}
}
but it prints 01:00:00.100 instead of 00:00:00.100, why?

Other way to solve this. Actually time diff that you having is not millisecs of current time. Its is just time diff, so make a simple division of that u can have hours:mins:secs.
And its quite fast.
Date start = GregorianCalendar.getInstance().getTime();
Thread.sleep(100);
Date end = GregorianCalendar.getInstance().getTime();
long longVal = end.getTime() - start.getTime();
long hours = longVal / 3600000;
long mins = (longVal % 3600) / 60000;
long secs = longVal % 60000;
System.out.println(hours + " " + mins + " " + secs);

You have mixed up two concepts:
You are measuring a time interval (difference between TWO points in time)
You are printing a date (ONE single point in time)
The two are not compatible, you will always get such strange effects. In your case, as pointed out on the other comments, the time zone gets mixed in. The concept of time zones exists only for dates (point in time), but makes no sense for intervals.
You can use the Jodatime library or the JSR 310: Date and Time API (coming with Java 8 I think).
With Jodatime you can explicitely construct a interval:
DateTime start = new DateTime(2004, 12, 25, 0, 0, 0, 0);
DateTime end = new DateTime(2005, 1, 1, 0, 0, 0, 0);
Period period = new Period(start, end);
and then format it with a PeriodFormatter
PeriodFormatter daysHoursMinutes = new PeriodFormatterBuilder()
.appendDays()
.appendSuffix(" day", " days")
.appendSeparator(" and ")
.appendMinutes()
.appendSuffix(" minute", " minutes")
.appendSeparator(" and ")
.appendSeconds()
.appendSuffix(" second", " seconds")
.toFormatter();
System.out.println(daysHoursMinutes.print(period));
By separating the concepts of ONE point in time and the time between TWO points in time, you can make sure that there aren't any other surprises (e.g. leap seconds).

It's a timezone issue. DateFormat.format() will by default format the date in your default time zone, which seem to be UTC+1.
You should set the timezone for timeFormat to UTC:
timeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(timeFormat.format(diff));
Also, you should use HH instead of hh in your DateFormat. hh is for 12-hour clock.
new SimpleDateFormat("HH:mm:ss.SSS");
Update :
But there is some other major issue. Currently you are trying to format a duration, which you should not do. Java Date API, do not have any concept of period or duration.
The value which you get from formatting is nothing but the number of milliseconds (equivalent to the difference) from epoch. It's returning a Date object, instead. Although the result might seem correct, but technically, the difference between two dates denotes a period or duration, which is not the same as Date (which denotes a particular instant of time).
You should consider moving to Joda Time for this task, which has classes representing these concepts like Period, Instant, and Duration.

Because your time zone is GMT+1.
If you read the documentation, you'll find what getTime() does:
Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
represented by this Date object.
So 100 ms means January 1, 1970, 00:00:00.100 GMT, which is January 1, 1970, 01:00:00.100 GMT+1.
You can simply set the time zone you want your time converted to:
timeFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
And you want 24h-style format: HH:mm:ss.SSS, otherwise it will show 12 instead of 00 hours.
EDIT: as jarnbjo said: you're trying to apply a date formatter to an interval of time, which obviously won't work as you expect. There's no such time interval formatters in the Java API. You'll have to write your own.

Related

Java Duration error from a day to another

I found a very simple problem using Java Duration.
LocalTime SaturdayStart = LocalTime.of(22, 30);
LocalTime SaturdayEnd = LocalTime.of(01, 00);
System.out.println(SaturdayStart);
System.out.println(SaturdayEnd);
System.out.println(Duration.between(SaturdayStart, SaturdayEnd));
The output from this code is:
22:30
01:00
PT-21H-30M
And this is the problem. Instead of 21H, I wanted the duration to be 2H-30M. What is causing the method to be unable to see the "day change" between the two times?
Remember that LocalTime just represents a single time, in one day, without a time zone.
Since it represents the time you see on the clock in one day, you can't use it to calculate differences between 22:30 today and 01:00 the next day. Your two LocalTime object represent 22:30 today, and 01:00 today respectively.
To take the day into account, you need a LocalDateTime. This represents not only a time (without a time zone), but also the date in the ISO-8601 calendar system. You can create the two LocalDateTime objects like this:
LocalDateTime start = LocalDateTime.of(LocalDate.now(), LocalTime.of(22, 30));
LocalDateTime end = start.plusDays(1).withHour(1).withMinute(0);
And then you can get the duration:
Duration d = Duration.between(start, end);
System.out.println(d);
By the way, the - characters you get in your wrong output are not delimiters for different components. They are negative signs. This is because you are subtracting 22:30 from 01:00, which is like subtracting a bigger number from a smaller number, you get a negative number.
The returned Duration interval has data, whether the StartTime occurs after EndTime or not, which can be used for further processing; like this
LocalTime SaturdayStart = LocalTime.of(22, 30);
LocalTime SaturdayEnd = LocalTime.of(01, 00);
System.out.println(SaturdayStart);
System.out.println(SaturdayEnd);
Duration interval = Duration.between(SaturdayStart, SaturdayEnd);
interval = interval.isNegative() ? interval.plusDays(1) : interval;
System.out.println(interval);
java.time.Duration is modelled on ISO-8601 standards and PT-21H-30M means a duration of 21 hours and 30 minutes where the minus sign indicates that the end time is earlier than the start time. Therefore, you can not get what you want unless you consider a date with time and the type representing both, date and time is LocalDateTime. You can choose any date and combine it with a time to get a LocalDateTime.
For any given date, if the start time is after the end time, reset the end date-time to midnight, then add one day to it and finally set its time to the end time.
Once you have the duration, you can create a formatted string by getting the hours, minutes, seconds etc. from it. With Java-9 some more convenience methods were introduced which makes it easier.
Demo:
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Main {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalTime startTime = LocalTime.of(22, 30);
LocalTime endTime = LocalTime.of(01, 00);
LocalDateTime startDateTime = today.atTime(startTime);
LocalDateTime endDateTime = today.atTime(endTime);
if (startDateTime.isAfter(endDateTime)) {
endDateTime = endDateTime.with(LocalTime.MIN).plusDays(1).with(endTime);
}
Duration duration = Duration.between(startDateTime, endDateTime);
// Default format
System.out.println(duration);
// Custom format
// ####################################Java-8####################################
String formattedDuration = String.format("%dH-%dM-%dS", duration.toHours(), duration.toMinutes() % 60,
duration.toSeconds() % 60);
System.out.println(formattedDuration);
// ##############################################################################
// ####################################Java-9####################################
formattedDuration = String.format("%dH-%dM-%dS", duration.toHoursPart(), duration.toMinutesPart(),
duration.toSecondsPart());
System.out.println(formattedDuration);
// ##############################################################################
}
}
Output:
PT2H30M
2H-30M-0S
2H-30M-0S

Joda-time off-by-one error when counting days after 1918-03-24

Calculating the number of days between 1900-01-01 and a date after 1918-03-24 using Joda-Time seems to give an off-by-one result.
Using Java 8 java.time gives the correct result. What is the reason for Joda-Time not counting 1918-03-25?
Using Joda-time v2.9.9.
public static void main(String[] args) {
jodaDiff("1918-03-24");
javaDiff("1918-03-24");
jodaDiff("1918-03-25");
javaDiff("1918-03-25");
jodaDiff("1918-03-26");
javaDiff("1918-03-26");
jodaDiff("2017-10-10");
javaDiff("2017-10-10");
}
private static void jodaDiff(String date) {
DateTime start = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeZone.forID("UTC"));
DateTimeFormatter dateDecoder = DateTimeFormat.forPattern("YYYY-MM-dd");
DateTime end = dateDecoder.parseDateTime(date);
int diff = Days.daysBetween(start, end).getDays();
System.out.println("Joda " + date + " " + diff);
}
private static void javaDiff(String date) {
LocalDate start = LocalDate.parse("1900-01-01");
LocalDate end = LocalDate.parse(date);
int diff = (int) ChronoUnit.DAYS.between(start, end);
System.out.println("Java " + date + " " + diff + "\n");
}
Output:
Joda 1918-03-24 6656
Java 1918-03-24 6656
Joda 1918-03-25 6656
Java 1918-03-25 6657
Joda 1918-03-26 6657
Java 1918-03-26 6658
Joda 2017-10-10 43015
Java 2017-10-10 43016
The problem is that your DateTimeFormatter is using the system default time zone. Ideally, you should parse to LocalDate values instead of DateTime, but you can fix it by using UTC for the formatter anyway:
DateTimeFormatter dateDecoder = DateTimeFormat.forPattern("YYYY-MM-dd").withZoneUTC();
To parse with LocalDate instead, just use:
org.joda.time.LocalDate start = new org.joda.time.LocalDate(1900, 1, 1);
DateTimeFormatter dateDecoder = DateTimeFormat.forPattern("YYYY-MM-dd");
org.joda.time.LocalDate end = dateDecoder.parseLocalDate(date);
(Obviously you don't need to fully-qualify it if you're not using Java 8.)
#Jon Skeet's answer is correct and direct to the point. I'd just like to add more details about what's happening and why you get these results (as you asked in the comments - and Jon also replied with a hint, that's also correct).
Your JVM default timezone is probably Europe/London (or any other that has a DST change in March 24th 1918). You can check that by using DateTimeZone.getDefault() in Joda-Time and ZoneId.systemDefault() in Java 8.
The start date you created in Joda is 1900-01-01T00:00Z (January 1st 1900 at midnight in UTC). The end date, though, is created only by using the year, month and day. But the DateTime also needs the time (hour/minute/second/millisecond) and a timezone. As those are not specified, it's set to midnight at the JVM default timezone (which is not guaranteed to be UTC - depending on the JVM configuration, you can get a different result).
Assuming your default timezone is London (that's how I could reproduce the problem - in my JVM default timezone (America/Sao_Paulo) it doesn't happen).
In March 25th 1981, London was in DST, so when you create your end date with 1918-03-25, the result is March 25th 1981 at midnight in London timezone - but due to DST change, the result is 1918-03-25T00:00+01:00 - during DST, London uses the offset +01:00, which means it's one hour ahead of UTC (so this end date is equivalent to 1918-03-24T23:00Z - or March 24th 1981 at 11 PM in UTC).
So, the difference in hours is 159767, which is not enough to complete 6657 days, so the difference is 6656 days (the rounding is always to the lowest value - the difference must be at least 159768 hours to complete 6657 days).
When you use a LocalDate, though, the time and DST effects are not considered (a LocalDate has only day, month and year), and you get the correct difference. If you set the end date to UTC, as well, you also get the correct results because UTC doesn't have DST changes.
By the way, if you use Java 8 ZonedDateTime, and use the start date with UTC and end date with London timezone (instead of using a LocalDate), you get the same difference in the results.
Not directly related, but in Joda-Time you can use the constant DateTimeZone.UTC to refer to UTC - calling forID("UTC") is redundant, as it returns the constant anyway (DateTimeZone.forID("UTC")==DateTimeZone.UTC returns true).
Joda-time off-by-one error when counting days after 1918-03-24
Try this, I corrected your program It gives you excepted answer with comparison with Java
public static void main(String[] args) {
jodaDiff("1918-03-24");
javaDiff("1918-03-24");
jodaDiff("1918-03-25");
javaDiff("1918-03-25");
jodaDiff("1918-03-26");
javaDiff("1918-03-26");
jodaDiff("2017-10-10");
javaDiff("2017-10-10");
}
private static void jodaDiff(String date) {
DateTime start = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeZone.forID("UTC"));
DateTime end = new DateTime(date);
int diff = Days.daysBetween(start.toLocalDate(), end.toLocalDate()).getDays();
System.out.println("Joda " + date + " " + diff);
}
private static void javaDiff(String date) {
LocalDate start = LocalDate.parse("1900-01-01");
LocalDate end = LocalDate.parse(date);
int diff = (int) ChronoUnit.DAYS.between(start, end);
System.out.println("Java " + date + " " + diff + "\n");
}
DateTime start = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeZone.forID("UTC"));
DateTimeFormatter dateDecoder = DateTimeFormat.forPattern("YYYY-MM-dd").withZone(DateTimeZone.forID("UTC"));
When you are creating first date, you are fixing the zone, with the second you don't. So either remove the zone, or set the same in both places.
You could also convert both DateTime to LocalDate, it also works for this example, but first solution should be a better case.

Converting minutes since midnight to 24-hour time

I have minutes since midnight.
Eg 3Am is represented as = 180 (found using 3*60)
Now I need to convert it into 24 hour time format HH24 :mm = 03:00
How can we use simple date formatter/calender for this?
I would use maths, forcing the date time library to do this won't be any simpler (as it expects milli-seconds and time zone)
int mins = 180;
String hhmm = String.format("%02d:%02d", mins / 60, mins % 60);
To do much the same thing with Calendar (which will handle daylight savings you can do)
int mins = 180;
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, mins/60);
cal.set(Calendar.MINUTE, mins % 60);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
String hhmm = sdf.format(cal.getTime());
System.out.println(hhmm);
prints
03:00
However on the days when daylight savings changes you could get 02:00 or 04:00
The answer by Peter Lawrey is correct, as per usual.
Joda-Time
My added value is to give an example with an alternative library, Joda-Time, as the java.util.Date & .Calendar classes are notoriously troublesome and should be avoided.
LocalTime
Both Joda-Time and the new java.time package in Java 8 (inspired by Joda-Time) offer a LocalTime class to represent a time-only without any date or time zone. Sounds like this applies to your needs.
Just be very sure that you do not need more than LocalTime. If this data is meant to the number of minutes since midnight in Paris, and you might mix in other data that represents date-times in New York or Auckland, then you should be using the DateTime class instead of LocalTime. Naïve programmers who think/hope that ignoring time zone makes things simpler are headed for big trouble.
Example Code
Some example code in Joda-Time 2.4.
// Input
int minutes = 180;
int millisecondsSinceAnyMidnight = ( minutes * 60 * 1000 );
LocalTime localTime = LocalTime.fromMillisOfDay( millisecondsSinceAnyMidnight );
// Output
String outputDefault = localTime.toString();
DateTimeFormatter formatter = DateTimeFormat.forPattern( "HH:mm" );
String outputHHMM = formatter.print( localTime );
// Dump to console.
System.out.println( "outputDefault: " + outputDefault );
System.out.println( "outputHHMM: " + outputHHMM );
When run.
outputDefault: 03:00:00.000
outputHHMM: 03:00

Using Joda-Time to get UTC offset for a given date and timezone

I have dates in the format 20Jan2013, 08Aug2012 etc, with their own specific timezones. So for example, 20Jan2013 might have a timezone ID of Australia/Melbourne, and 08Aug2012 might have an ID of Europe/London. What I want to do is, based on these timezones and the dates, calculate the UTC offset for that timezone on the given date. I've come up with this so far:
DateTimeFormatter dtf = DateTimeFormat.forPattern("ZZ");
DateTimeFormatter dtf1 = DateTimeFormat.forPattern("ddMMMYYYY");
DateTimeZone zone = DateTimeZone.forID("Australia/Melbourne");
DateTime thisDate = dtf1.parseDateTime("30Jul2013");
System.out.println("\nZone: " + thisDate.withZone(zone));
This gives me the output:
Zone: 2013-07-30T00:00:00.000+10:00
This is correct, but I would like to extract just the UTC offset from this, which in this case is +10:00. I've looked for ways to do this but can't find anything. Is there any way I can do this? The only option I see is to convert the output to a String and use the substring method to get the UTC offset.
The above code does take DST (Daylight Saving Time) into account. So for example if I had:
DateTime thisDate = dtf1.parseDateTime("30Jan2013");
The output would be: 2013-01-30T00:00:00.000+11:00
(+11:00 at the end instead of +10:00)
So basically all I need to do is find a way to extract +11:00 from 2013-07-30T00:00:00.000+11:00. Please help!
Simple Method for Obtaining Timezone Name and Offset in Hours
public static String getCurrentTimeZoneOffset() {
DateTimeZone tz = DateTimeZone.getDefault();
Long instant = DateTime.now().getMillis();
String name = tz.getName(instant);
long offsetInMilliseconds = tz.getOffset(instant);
long hours = TimeUnit.MILLISECONDS.toHours( offsetInMilliseconds );
String offset = Long.toString( hours );
return name + " (" + offset + " Hours)";
// Example: "Mountain Standard Time (-7 Hours)"
}
Couple caveats:
This gets the default DateTimeZone from JodaTime. You can modify it to accept a specific DateTimeZone that is passed into the method.
This returns it in a format like "Mountain Standard Time (-7 Hours)" but you can format it as you see fit quite easily.
Hope that helps.
JP
In order for Joda to give the correct offset, you must provide a datetime instant.Without a datetime instant, it is impossible to calculate the offset since we have different offsets(daylight savings). This is how I would use Joda to get offset in + HH:mm format :
int offsetInMillis = DateTimeZone.forID(zoneId).getOffset(new DateTime().getMillis());
String offset = String.format("%02d:%02d", Math.abs(offsetInMillis / 3600000),
Math.abs((offsetInMillis / 60000) % 60));
offset = (offsetInMillis >= 0 ? "+" : "-") + offset;
If you just need the timezone offset, use DateTimeZone.forID() to get the time zone and then tz.getOffset(instant) to get the offset to UTC in milliseconds.
It may look odd that you need an instant to calculate the offset to UTC but this is necessary to take Daylight Savings into account as well as changes in the timezone. Yes, countries change their timezones once in a while:
Why does timezone data change?
Timezone settings are adopted locally, and there is no world timezone authority.
EDIT This gives you the correct result:
DateTimeFormatter dtf1 = DateTimeFormat.forPattern("ddMMMYYYY");
DateTimeZone zone = DateTimeZone.forID("Australia/Melbourne");
DateTime thisDate = dtf1.parseDateTime("30Jul2013").withZone(zone);
assertEquals( 10 * CommonConstants.MILLISECONDS_PER_HOUR,
zone.getOffset( thisDate ) );
thisDate.get
Java 8 introduced better Date and Time handling to address some of the language's previous limitations in that area. A few of my projects have started to use it rather than Joda.
Using the java.time package:
ZonedDateTime dateTime = LocalDate.of(2013 , 1 , 20).atStartOfDay( ZoneId.of("Australia/Melbourne"));
ZoneOffset zo = dateTime.getOffset();
int offset = zo.getTotalSeconds();
long hours = TimeUnit.SECONDS.toHours(offset);
long minutes = TimeUnit.SECONDS.toMinutes(offset % 3600);
The hours variable is set to 11 and the minutes to 0.
It also calculates the minutes-offset, for time zones that are partial hours, such as Newfoundland and Labrador in eastern Canada:
ZonedDateTime dateTime = LocalDate.of(2013, 1, 20).atStartOfDay( ZoneId.of("Canada/Newfoundland"));
In this case, the offset is -03:30 (three and a half hours behind UTC), hours is -3 and minutes is -30.
For the String representation, rather than the integer number of hours and minutes, use the ZoneOffset's toString() method. So for the example above, use:
String offsetString = zo.toString();
When you know offset and timestamp so in order to get current time you can use
public static String formatMonthDayMinuteByGivenUtcOffset(long timestamp, int offset) {
return JODA_FORMATTER.print(createDateTime(timestamp, offset));
}

Converting local timestamp to UTC timestamp in Java

I have a milliseconds-since-local-epoch timestamp that I'd like to convert into a milliseconds-since-UTC-epoch timestamp. From a quick glance through the docs it looks like something like this would work:
int offset = TimeZone.getDefault().getRawOffset();
long newTime = oldTime - offset;
Is there a better way to do this?
Sadly, this seems to be the best way to do this:
public static Date convertLocalTimestamp(long millis)
{
TimeZone tz = TimeZone.getDefault();
Calendar c = Calendar.getInstance(tz);
long localMillis = millis;
int offset, time;
c.set(1970, Calendar.JANUARY, 1, 0, 0, 0);
// Add milliseconds
while (localMillis > Integer.MAX_VALUE)
{
c.add(Calendar.MILLISECOND, Integer.MAX_VALUE);
localMillis -= Integer.MAX_VALUE;
}
c.add(Calendar.MILLISECOND, (int)localMillis);
// Stupidly, the Calendar will give us the wrong result if we use getTime() directly.
// Instead, we calculate the offset and do the math ourselves.
time = c.get(Calendar.MILLISECOND);
time += c.get(Calendar.SECOND) * 1000;
time += c.get(Calendar.MINUTE) * 60 * 1000;
time += c.get(Calendar.HOUR_OF_DAY) * 60 * 60 * 1000;
offset = tz.getOffset(c.get(Calendar.ERA), c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH), c.get(Calendar.DAY_OF_WEEK), time);
return new Date(millis - offset);
}
(I know that this is several months past post date, but it's a problem that is very useful to solve when working with text messages on Android. dave's answer is wrong.)
Use a Calendar to get what the offset was at the local Epoch, then add that to the local-epoch timestamp.
public static long getLocalToUtcDelta() {
Calendar local = Calendar.getInstance();
local.clear();
local.set(1970, Calendar.JANUARY, 1, 0, 0, 0);
return local.getTimeInMillis();
}
public static long converLocalTimeToUtcTime(long timeSinceLocalEpoch) {
return timeSinceLocalEpoch + getLocalToUtcDelta();
}
Using Joda Time it would be like this :
DateTime dt = new DateTime(year, month, day, hour, minute, 0, 0, DateTimeZone.forID("local");
dt.getMillis();
EDITED: Sorry, this is the correct version :
DateTime dt = new DateTime(timestamp, DateTimeZone.forID("local");
dt.getMillis();
Actually, Chris Lercher hit the nail on the head, but he only made it in a short comment, so I wanted to expand on it.
Imagine two stopwatches; one is somewhere where UTC is the local time on Jan 1, 1970, and the other stopwatch is local to your area (let's say that it's in New York, 5 hours after UTC). At UTC midnight, on Jan 1, 1970, the UTC stopwatch is started. 5 hours later, your local stopwatch is started. Those two stopwatch times differ by some amount, determined only by what the difference between UTC was from your local time at local midnight on Jan 1, 1970. Any daylight-saving shenanigans, since then, have no bearing on the difference between those stopwatches. So, any DST corrections for your present time or for the times you're converting, are irrelevant. All you need is how much later your local stopwatch started on Jan 1, 1970.
As Chris pointed out, this is just: getOffset(0L), so:
int offset = TimeZone.getDefault().getOffset(0L);
long newTime = oldTime - offset;
... should work fine. However....
To help really grasp this, note this: that "0L" in getOffset() is the milliseconds since the UTC epoch (which is the only real epoch). So, your offset variable is going to have the number of seconds of offset at midnight UTC (ie, when it was, say, 19:00 on 12/31/1969 in New York). If your local time switched to/from daylight-saving in those last hours before local midnight, then getOffset(0L) wouldn't be correct. You need to know what your daylight-saving status was at local midnight, not UTC's midnight.
I'd be surprised if this were the case, anywhere (ie, any timezone which changed to/from DST between their local midnight and UTC midnight of Jan 1, 1970). However, just for fun, a cheap hack to help guard against this would be to check if the offset changed in those hours:
// Offset at UTC midnight
int offset = TimeZone.getDefault().getOffset(0L);
long newTime = oldTime - offset;
// Offset at Local midnight
int localMidnightOffset = TimeZone.getDefault().getOffset(-offset);
Here, localMidnightOffset will be what the timezone offset was at a time -offset milliseconds after UTC midnight in 1970. If no DST change happened, then localMidnightOffset will equal offset, and you're done. If some DST change did occur, then you might have to hunt around... probably keep doing a
localMidnightOffset = TimeZone.getDefault().getOffset(-localMidnightOffset)
until it stops changing... and hope you don't get caught in an endless loop. I'm curious to see if anybody has a guaranteed-converging solution.
Kinda makes you wish the world were flat, huh?
No, that definitely won't work - it doesn't take DST into account. You can't just use getOffset(oldTime) either, as the DST may have changed between the two...
You could use getOffset(oldTime) to get an initial guess at the timestamp, then check getOffset(utcTime) to see whether they're the same or not. It gets fun, basically.
Joda Time should support this using DateTimeZone.getOffsetFromLocal but that's slightly broken (IMO) around DST transitions.
All of this really depends on what you mean by "milliseconds since local epoch". If you really mean elapsed milliseconds since local 1970, you could just find out the offset at that date, and apply that regardless. Typically (IME) a "local" millis value doesn't mean quite that though - it means "the number of millis to get to a particular date and time (e.g. April 9th 2010, 18:06pm) in UTC, but in respect of a different time zone". In other words, it can represent ambiguous or impossible date/time combinations based on DST transitions.
static final long localTimeZoneoffset = TimeZone.getDefault().getOffset(0L);
static final long dstOffset = TimeZone.getDefault().getDSTSavings();
long offsetOftime = TimeZone.getDefault().getOffset(time.getTime());
long timeinmilli = 0L;
if(offsetOftime != localTimeZoneoffset)
timeinmilli = time.getTime()+localTimeZoneoffset+dstOffset;
else
timeinmilli = time.getTime()+localTimeZoneoffset;
return new Timestamp(timeinmilli);
This worked for me to convert to UTC.
May be this can help you i have try this way. Please comment me if there is any best and optimize way to convert local time to UTC timestamp.
String mDate= "Jul 21,2016 1:23 PM";
String mDateFormat =""MMM d,yyyy h:mm a";
Call : getConvertedTimeToUTC(mDate,mDateFormat);
public String getConvertedTimeToUTC(String ourDate, String mDateFormat) {
try {
SimpleDateFormat fmt = new SimpleDateFormat(mDateFormat);
fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
Date value = fmt.parse(ourDate);
if (value != null)
return String.valueOf(value.getTime() / 1000);
else
return null;
} catch (Exception e) {
ourDate = "00-00-0000 00:00";
}
return ourDate;
}
Here is the result : (Ref : check conversion)
Result 1469107380
GMT: Thu, 21 Jul 2016 13:23:00 GMT
Your time zone: Thursday 21 July 2016 06:53:00 PM IST GMT+5:30

Categories

Resources