How can I get the current local wall clock time (in number of millis since 1 Jan 1970) in London? Since my application can run on a server in any location, I think I need to use a TimeZone of "Europe/London". I also need to take Daylight Savings into account i.e. the application should add an hour during the "summer".
I would prefer to use the standard java.util libraries.
Is this correct?
TimeZone tz = TimeZone.getTimeZone("Europe/London") ;
Calendar cal = Calendar.getInstance(tz);
return cal.getTime().getTime() + tz.getDSTSavings();
Thanks
I'm not sure what this quantity represents, since the "number of millis since 1 Jan 1970" doesn't vary based on location or daylight saving. But, perhaps this calculation is useful to you:
TimeZone london = TimeZone.getTimeZone("Europe/London");
long now = System.currentTimeMillis();
return now + london.getOffset(now);
Most applications are better served using either UTC time or local time; this is really neither. You can get the UTC time and time in a particular zone like this:
Instant now = Instant.now(); /* UTC time */
ZonedDateTime local = now.atZone(ZoneId.of("Europe/London"));
Others have said that it may well not be a good idea to do this - I believe it depends on your situation, but using UTC is certainly something to consider.
However, I think you've missed something here: the number of seconds which have occurred since January 1st 1970 UTC (which is how the Unix epoch is always defined - and is actually the same as in London, as the offset on that date was 0) is obtainable with any of these expressions:
System.currentTimeMillis()
new Date().getTime()
Calendar.getInstance().getTime().getTime()
If you think about it, the number of milliseconds since that particular instant doesn't change depending on which time zone you're in.
Oh, and the normal suggestion - for a much better date and time API, see Joda Time.
To get the current time in London:
SimpleDateFormat f = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
f.setTimeZone(TimeZone.getTimeZone("Europe/London"));
System.out.println(f.format(GregorianCalendar.getInstance().getTime()));
Related
Our client sends us a start and end date-time in a text file as a String in the below format
2019-10-07 11:07 AM
All date-time is in one timezone. We calculate the difference between the start and end date-time to calculate the hours worked. The hours worked calculation goes wrong when the transition of daylight savings time happens. They are not sending enough information for us to calculate correctly.
I am about to recommend that they send us more information so that we can address this issue. What is a good solution here? What date-time format should we recommend to them that will help us address the DST change and calculate hours worked correctly.
We use Java.
Getting it right is not obvious
They are telling you their local time, and you can infer the time zone (because "all date is in one time zone").
The basic calculation looks like this:
ZoneId pacific = ZoneId.of("America/Los_Angeles");
DateTimeFormatter local = DateTimeFormatter.ofPattern("uuuu-MM-dd hh:mm a").withZone(pacific);
ZonedDateTime start = ZonedDateTime.parse("2022-11-06 01:30 AM", local);
ZonedDateTime until = ZonedDateTime.parse("2022-11-07 01:30 AM", local);
long hours = start.until(until, ChronoUnit.HOURS);
System.out.printf("%d hours elapsed%n", hours);
This prints "25 hours elapsed." In the Pacific time zone, November 6, 2022, is 25 hours long, because when daylight saving ends in the autumn, the clock is set back one hour. If someone tells you it's 1:00 AM, you don't know if midnight was one hour ago or two.
The default offset heuristic
What you really need is the offset, and you have to rely on some heuristic for that. By default, ZonedDateTime chooses one instant from multiple ambiguous local date-times by selecting the earliest offset (the "summer" offset).
Specifying the offset
If that's not what you want, you can override the offset explicitly. For example, maybe you process these time stamps close to real-time, and you can guess what the offset should be based on the current time. Or maybe you know that these local time stamps are always processed in chronological order; by tracking the latest time you've seen, and noting if an earlier time stamp follows, you can detect the clock set back and change the offset.
The ZonedDateTime.ofLocal() and ZonedDateTime.ofStrict() functions can be used to explicitly control the offset.
OffsetDateTime
Alternatively, you might request that they include the offset in the timestamp string. Usually this would be indicated with a signed number of hours and minutes: "-07:00" or "-0800". This will provide unambiguous interpretation of times during DST transitions.
Here is an example using OffsetDateTime. First, if the offset uses a colon, as in "2019-10-07T11:07:00+01:00", it is a standard format, and can be parsed like this:
OffsetDateTime start = OffsetDateTime.parse("2019-10-07T11:07:00+01:00");
If the colon is missing, you need a formatter to handle the non-standard input:
DateTimeFormatter odt = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendOffsetId()
.toFormatter();
OffsetDateTime when = OffsetDateTime.parse("2019-10-07T11:07:00+01:00", odt);
From there, the calculation is the same as with ZonedDateTime:
OffsetDateTime start = OffsetDateTime.parse("2022-11-06T01:00:00-07:00", odt);
OffsetDateTime until = OffsetDateTime.parse("2022-11-07T01:54:00-08:00", odt);
long hours = start.until(until, ChronoUnit.HOURS);
System.out.printf("%d complete hours elapsed.%n", hours);
Duration duration = Duration.between(start, until);
System.out.println("Full duration: " + duration);
This is simple task. The DateTimeFormatter class gives you all the info you need. 2019-10-07 11:07 AM Your format would be 'yyyy-MM-dd hh:mm a' and you should use LocalDateTime class. But since you need to take into account daylight savings time then you might want to use classes ZonedDateTime or OffsetDateTime and provide your timezone. It might be an overkill, but I once worked on the project where I needed to parse Strings to Dates without knowing the format in advance. So, here is the article I wrote on how to do that: Java 8 java.time package: parsing any string to date
I have a Date with the actual time of my system (I live in Spain). I need to change it to UTC-1, but it doesn't matter if I write "UTC-1" or "UTC-2", it always gives me the same time less 2 hours, I mean:
My system hour (time_utc): 11:00 13/04/2021
Try UTC-1 (time): 09:00 13/04/21
Try UTC-2 (time): 09:00 13/04/21
I have this code:
Date time_utc = new Date();
DateFormat convertidor = new SimpleDateFormat("yyyy-MM-dd HH:00:00.000");
convertidor.setTimeZone(TimeZone.getTimeZone("UTC-1"));
time = convertidor.format(time_utc);
Why it doesn't work? Can anyone helps me? Thanks a lot!
¡Hola!
You can do that in a pretty short way using java.time (if you are allowed and willing to do so).
There are special classes that represent a moment in time in different time zones of offsets. One of them is an OffsetDateTime, see this example:
public class Main {
public static void main(String[] args) {
// create one of your example date times in UTC
OffsetDateTime utcOdt = OffsetDateTime.of(2021, 4, 13, 11, 0, 0, 0, ZoneOffset.UTC);
// and print it
System.out.println(utcOdt);
/*
* then create another OffsetDateTime
* representing the very same instant in a different offset
*/
OffsetDateTime utcPlusTwoOdt = utcOdt.withOffsetSameInstant(ZoneOffset.ofHours(2));
// and print it
System.out.println(utcPlusTwoOdt);
// do that again to see "the other side" of UTC (minus one hour)
OffsetDateTime utcMinusOneOdt = utcOdt.withOffsetSameInstant(ZoneOffset.ofHours(-1));
// and print that, too.
System.out.println(utcMinusOneOdt);
}
}
It outputs the following three lines:
2021-04-13T11:00Z
2021-04-13T13:00+02:00
2021-04-13T10:00-01:00
As you can see, the time of day is adjusted according to the offset.
The output could be formatted in your desired style if needed (this currently just uses the toString() method of OffsetDateTime).
UPDATE
You can achieve the output formatted as desired by defining the pattern as uuuu-MM-dd HH:mm when using a java.time.format.DateTimeFormatter.
Just add the following lines to the example above:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm");
System.out.println(utcOdt.format(dtf));
System.out.println(utcPlusTwoOdt.format(dtf));
System.out.println(utcMinusOneOdt.format(dtf));
This would then output
2021-04-13 11:00
2021-04-13 13:00
2021-04-13 10:00
And if you really want fix zeros for seconds and millis, then create your DateTimeFormatter like this:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:00.000");
which will cause output like this:
2021-04-13 11:00:00.000
2021-04-13 13:00:00.000
2021-04-13 10:00:00.000
As a supplement to the good answer by deHaar:
As Matt Johnson-Pint already asked, do you need to convert to a different time zone? This would be the most typical. If so, use that time zone, not just a UTC offset of -1. By all probability that time zone has used other offsets in the past and may well do so in the future. So -01:00 isn’t safe. A real time zone ID like Atlantic/Cape_Verde is safer.
You don’t need to go through the current time in your own time zone and convert. java.time can directly give you the current time in another time zone or at a specific UTC offset.
java.time can also truncate a time to whole hours.
So for example:
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS");
ZoneId zone = ZoneId.of("Atlantic/Cape_Verde");
ZonedDateTime nowInCaboVerde = ZonedDateTime.now(zone);
System.out.println(nowInCaboVerde);
System.out.println(nowInCaboVerde.truncatedTo(ChronoUnit.HOURS)
.format(formatter));
Output:
2021-04-14T03:12:28.272010-01:00[Atlantic/Cape_Verde]
2021-04-14 03:00:00.000
PS Cabo Verde/Cape Verde was at offset -02:00 until 1975.
What went wrong in your code?
This is how confusingly the old TimeZone class behaves and one of the reasons why you should never use it: When given a time zone ID that it does not recognize, it returns GMT and pretends all is well. UTC-1 is not a recognized time zone ID. In case it didn’t make sense to refer to a real time zone and you needed the offset -01:00 from UTC, you might have used GMT-1 or GMT-01:00. Yes, TimeZone refers to UTC as GMT even though they are not strictly speaking the same.
I have written below code which is running, and giving output. But I'm not sure It's a right one.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = new Date();
sdf.setTimeZone(TimeZone.getTimeZone("GMT-7"));
String value = sdf.format(date);
System.out.println(value);
Date date2 = sdf.parse(value);
long result = date2.getTime();
System.out.println(result);
return result;
The above code what I'm trying is, I just need to get the current time of GMT time zone and convert it as epoch format which is gonna used in Oracle db.
Can someone tell me that format, and the above code is right?
First, you should not store time since the epoch as a timestamp in your database. Look into the date-time datatypes that your DMBS offers. In Oracle I think that a date column will be OK. For most other DBMS you would need a datetime column. timestamp and timestamp with timezone may be other and possibly even sounder options depending on your exact requirements.
However, taking your word for it: Getting the number of milliseconds since the epoch is simple when you know how:
long millisecondsSinceEpoch = System.currentTimeMillis();
System.out.println(millisecondsSinceEpoch);
This just printed:
1533458641714
The epoch is defined in UTC, so in this case we need to concern ourselves with no other time zones.
If you needed seconds rather than milliseconds, it’s tempting to divide by 1000. However, doing your own time conversions is a bad habit since the libraries already offers them, and using the appropriate library methods gives clearer, more explanatory and less error-prone code:
long secondsSinceEpoch = Instant.now().getEpochSecond();
System.out.println(secondsSinceEpoch);
1533458641
You said:
I just need to get the current time of GMT time zone…
Again taking your word:
OffsetDateTime currentTimeInUtc = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println(currentTimeInUtc);
long millisecondsSinceEpoch = currentTimeInUtc.toInstant().toEpochMilli();
System.out.println(millisecondsSinceEpoch);
2018-08-05T08:44:01.719265Z
1533458641719
I know that GMT and UTC are not exactly the same, but for most applications they can be (and are) used interchangeably.
Can someone tell me (if) the above code is right?
When I ran your code just now, its output agreed with mine except the milliseconds were rounded down to whole thousands (whole seconds):
1533458641000
Your code has some issues, though:
You are using the old, long out-dated and poorly designed classes SimpleDateFormat, Date and TimeZone. The first in particular has a reputation for being troublesome. Instead we should use java.time, the modern Java date and time API.
Bug: In your format pattern string you are using lowercase hh for hour of day. hh is for hour within AM or PM, from 1 through 12, so will give you incorrect results at least half of the day. Uppercase HH is for hour of day.
Don’t use GMT-7 as a time zone. Use for example America/Los_Angeles. Of course select the time zone that makes sense for your situation. Edit: You said:
I just want to specify the timezone for sanjose. GMT-7 is refer to
sanjose current time.
I believe many places are called San Jose. If you mean San Jose, California, USA, you are going to modify your program to use GMT-8 every time California goes back to standard time and opposite when summer time (DST) begins?? Miserable idea. Use America/Los_Angeles and your program will work all year.
Since you ask for time in the GMT time zone, what are you using GMT-7 for at all?
There is no point that I can see in formatting your Date into a string and parsing it back. Even if you did it correctly, the only result you would get would be to lose your milliseconds since there are no milliseconds in your format (it only has second precision; this also explained the rounding down I observed).
Links
Oracle tutorial: Date Time explaining how to use java.time, the modern Java date and time API.
San Jose, California on Wikipedia
Why not use Calendar class?
public long getEpochTime(){
return Calendar.getInstance(TimeZone.getTimeZone("GMT-7")).getTime().getTime()/1000; //( milliseconds to seconds)
}
It'll return the current Date's Epoch/Unix Timestamp.
Based on Harald's Comment:
public static long getEpochTime(){
return Clock.system(TimeZone.getTimeZone("GMT-7").toZoneId() ).millis()/1000;
}
Here is a solution using the java.time API
ZonedDateTime zdt = LocalDateTime.now().atZone(ZoneId.of("GMT-7"));
long millis = zdt.toInstant().toEpochMilli();
I am getting current time from Ruby on Rails webservice in Unix Timestamp format (ie. in seconds from 1 Jan 1970), the timezone on server is UTC.
In Java I am trying to convert local current time to UTC time. But every time it is giving 6+ minutes ahead time. I want to get the difference of UTC current time and the time returned from service. My Java code is -
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
Date utc_current = new Date(System.currentTimeMillis());
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
long serverTime = 1424936268000L;
long resTime = sdf.getCalendar().getTimeInMillis() - serverTime;
System.out.println("Time Diff : " + resTime);
Where serverTime is the time I am getting from webservice. And the value for resTime shows negative value which is approx 6+ minutes.
So my question is why UTC timezone giving ahead time for System.currentTimeMillis?
In contrast to the assumption in a comment of of #JB Nizet the expressions sdf.getCalendar().getTimeInMillis() and System.currentTimeMillis() are not equivalent. Proof:
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
System.out.println("date via System.currentTimeMillis()=" + f.format(utc_current));
System.out.println("date via sdf.getCalendar()=" + f.format(new Date(resTime)));
Output:
date via System.currentTimeMillis()=2015-02-26T12:19:09
date via sdf.getCalendar()=1889-12-31T04:41:21
If you carefully study the source code of SimpleDateFormat and DateFormat you will find within the initialization part code like:
private void initializeDefaultCentury() {
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add( Calendar.YEAR, -80 );
parseAmbiguousDatesAsAfter(calendar.getTime());
}
The conclusion is to strictly avoid the method getCalendar() on your DateFormat-object. It is only used as intermediate mutable object for internal format and parse processing. It is hard to say what you will really get as time this way. Instead use directly System.currentTimeMillis() to compare your local time with server time.
Another problem is the pattern you use. "dd-MM-yyyy hh:mm:ss" is probably not correct because it uses the clock hour of half day in range 1-12 but the information for am/pm is missing. Use better the pattern symbol HH. Check the documentation of webservice for the right format.
Make sure the the clock on the server and on the client machine are synchronized. The 6 minutes could simply be an offset between the two.
I have this code:
Date now = new Date();
// the string is in UTC format, so a UTC date must be constructed, I don't know if that happens in this format
Date measure = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(utcDateTime);
long diff = now.getTime() - measure.getTime();
if (diff < 1000* 60 * 15) {
// measure is less then 15 minutes recent
do some work
}
When I get the diff, it includes the timezone. I know the Date object internally is UTC.
So what's wrong here?
While a Date object is indeed in UTC, your SimpleDateFormat may not be. I suspect it default's to the system time zone - that's certainly what experimentation would suggest. You can change this using DateFormat.setTimeZone. So if your text represents a UTC date/time, you should set the time zone of the formatter to UTC as well.
Or you could use Joda Time, which is a generally better date and time API :)