An old Stack Overflow posting suggests that the way to get the UTC timestamp in Java is the following:
Instant.now() // Capture the current moment in UTC.
Unfortunately this does not work for me. I have a very simple program (reproduced below) which demonstrates different behavior.
On Windows: the time is the local time and it is labeled with the offset with GMT
On Linux: the time is again the local time, and it is labeled correctly for the local timezone
Question: How do we display the UTC timestamp in a Java program?
My sample source code is as follows:
import java.time.Instant;
import java.util.Date;
public class UTCTimeDisplayer {
public static void main(String[] args) {
System.out.println(System.getProperty("os.name"));
Date currentUtcTime = Date.from(Instant.now());
System.out.println("Current UTC time is " + currentUtcTime);
}
}
Windows Output:
C:\tmp>java UTCTimeDisplayer
Windows 10
Current UTC time is Fri Jan 22 14:28:59 GMT-06:00 2021
Linux Output:
/tmp> java UTCTimeDisplayer
Linux
Current UTC time is Fri Jan 22 14:31:10 MST 2021
Your code:
Date.from(Instant.now())
You are mixing the terrible legacy classes with their replacement, the modern java.time classes.
Don’t.
Never use Date. Certainly no need to mix with java.time.Instant.
To explain your particular example, understand that among the Date class’ many poor design choices is the anti-feature of its Date#toString method implicitly applying the JVM’s current default time zone while generating its text.
You ran your code on two different JVMs that had different current default time zones. So you got different outputs.
Sun, Oracle, and the JCP gave up on the legacy date-time classes. So should we all. I recommend you not spend time trying understand Date, Calendar, SimpleDateFormat, and such.
You asked:
Question: How do we display the UTC timestamp in a Java program?
Instant.now().toString()
See that code run live at IdeOne.com.
2021-01-22T21:50:18.887335Z
You said:
On Windows: …
On Linux: …
You’ll get the same consistent results from Instant.now().toString() across Windows, Linux, BSD, macOS, iOS, Android, AIX, and so on.
Here is a table I made to guide you in transitioning from the legacy classes.
The java.util.Date object is not a real date-time object like the modern date-time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). When you print an object of java.util.Date, its toString method returns the date-time in the JVM's timezone, calculated from this milliseconds value. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFormat and obtain the formatted string from it.
I would suggest you simply use Instant.now() which you can convert to other java.time type.
The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
However, if you still want to use java.util.Date, use SimpleDateFormat as mentioned above.
Demo:
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
Date currentUtcTime = Date.from(Instant.now());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println("Current UTC time is " + sdf.format(currentUtcTime));
}
}
Output:
Current UTC time is 2021-01-22 21:53:07 UTC
suggests that the way to get the UTC timestamp in Java is the following:
Instant.now() // Capture the current moment in UTC.
This, and most answers in this thread, are misleading.
Instant represents an instant in time. It's 'solarflares' time: Absolutely not one iota about it represents anything that is invented by human brains, and UTC is a timezone: A human invention. The cosmos, the sun, astronomy - they have no idea what UTC is, and don't care - and that's what Instant is all about. Instants are devoid of such human concepts as 'hours' or 'days' or 'timezones'. It makes no sense to ask an instant what day it happened on. It cannot tell you; some event occurred: If I ask a russian from the 19th century when that happened, they'll likely give a completely different answer vs. if I ask someone living a mere 100 miles west, for example. Instant doesn't know which localization to apply and thus doesn't let you ask it this question - that's a good thing, objects should not expose methods to which any answer it gives is either gobbledygook or at least requires knowing about all sorts of surprising caveats.
Crucially, if you tell me '... in UTC', you surely can tell with exacting detail which month, which day, etcetera. And Instant does not do this, which is why it is misleading to say that a java.time.Instant represents a moment of time in UTC. It doesn't. It represents a moment in time (not in any particular timezone).
Yeah, internally Instant, just like Date, is just a light wrapper around what System.currentTimeMillis() returns: "millis since epoch", but the crucial thing to understand about it, is that 'UTC' is not part of what it means, and therefore, when you give an Instant instance to some other method (such as System.out.println, to a database via JDBC, etc), that method is under absolutely no obligation to assume that UTC is semantically relevant.
When you want to mix human notions of time keeping (years, days, months, hours, minutes, milliseconds, and, yeah, timezones) with the notion of a more or less absolute* time, the right answer is java.time.ZonedDateTime. Note that any representation of time in something that isn't java.time.* based is by definition broken, as it is in most programming languages - turns out time is a lot more complex than most takes on a library to represent it realize. The fact that java.time is in effect the 4th attempt at writing a time library should be ample indication that it's hard to get it right.
ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC);
THAT is what you want - that isn't just implementation-detail-wise what you want, but it is code that exactly describes what you mean: Right now, at the UTC time zone, stored in an object that semantically doesn't just store the right time but also stores, and tightly entangles into its very identity, that it is specifically in UTC and is not to be re-interpreted, moved to the local zone, or any other such shenanigans - at least, not unless you explicitly ask it to do so.
Date currentUtcTime = Date.from(Instant.now());
Note that Date is the old API and therefore necessarily broken. In this case, Date is a lying liar who lies - it doesn't represent a date, it represents an instant; it is badly named. (The second API is Calendar, also broken. For example, that is also a lying liar who lies: It doesn't represent a Calendar whatsoever. It represents some bizarre amalgamation of a zoned datetime and an instant and is fit to represent neither as a consequence). Any time you go to the Date API weirdness ensues, and something as simple as 'I just want the concept of the time, at some specific moment, in UTC' isn't possible in these APIs. You are now dependent on barely defined behaviour of all the various libraries up and down the chain - you're effectively stuck praying that they do the right thing, or delving into exotic settings to try to cajole these libraries into doing what you want.
TL;DR: Use java.time.
*) Note that ZonedDateTime is not absolute. For example, if you have the time January 20th, 2023, 8 in the morning, at Europe/Amsterdam, in the form of a ZonedDateTime object, then the amount of seconds that will pass between now and that moment sure seems like it does not change and will not change when e.g. amsterdam goes through an hour change due daylight savings. However, if the dutch government decrees that henceforth The Netherlands will no longer move the clocks at all and will stay in summer time forever (which is likely - EU directive is already in place, it's now just a matter of when), then at the moment the gavel lands, your appointment shifts by 1 hour exactly.
That hopefully provides crucial insight in the difference: Instant, representing events (hence why I like to call it 'solarflares time', to disentangle it from human time keeping concepts as much as possible), doesn't even understand the very concept of such a decision having an effect on things. ZonedDateTime on the other hand is inherently bound up in it - hence the Zone in ZonedDateTime.
If you want to store barber appointments and use Instant to do it, you WILL be an hour late or early sooner rather than later.
An Instant object and also a Date object by themselves
only contain a point in time, but no timezone information.
Furthermore, the toString() method of the Date class
implicitly chooses the timezone provided by the system environment,
which is not what you want.
Therefore you need to chose the timezone (in your case UTC) explicitly.
For example like this:
Instant instant = Instant.now();
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.UTC);
System.out.println("Current UTC time is " + offsetDateTime);
This will (independently from the operation system) print
Current UTC time is 2021-01-22T22:37:21.950354100Z
where the trailing Z denotes the zero timezone offset (i.e. UTC).
A simple method that could work!
My requirement was date time with milliseconds
2021-11-25 19:55:00.743
private String getUTCTimestamp() {
ZonedDateTime utc = ZonedDateTime.now(ZoneOffset.UTC);
return utc.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));
}
Instant.now() is essentially the period of time since the epoch, (midnight 1 January 1970 in UTC), but you are using a Date to present that instant. Date is a reflection of the instant with millisecond precision, but as explained in the documentation at https://docs.oracle.com/javase/8/docs/api/java/util/Date.html, presenting a date should be done using a Calendar, as the presentation of a Date depends on the host. Essentially Date wraps the instant but is displayed according to other factors.
The simplest approach now if you want to output the instant is to use OffsetDateTime so that you can elect to present the instant in your desired timezone - UTC in your case. Use either OffsetDateTime.now() or OffsetDateTime.ofInstant() but if you are using the instant within your application logic then just stick with Instant.
Sometimes your program has to work with older java versions, so here is an example for 1.5:
java.text.SimpleDateFormat tfGMT = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
java.util.Calendar cUTC = java.util.Calendar.getInstance (java.util.TimeZone.getTimeZone ("GMT+0"));
tfGMT.setCalendar (cUTC);
java.util.Date d= new java.util.Date ();
String s= tfGMT.format (d);
System.out.printf ("now=%s [unix ts=%d.%03d]\n", s, d.getTime()/1000, d.getTime()%1000);
Mind you, the first three lines don't have to be repeat at every call, but keep in mind that SimpleDateFormat is not thread-safe. (Simple solution: create one for each thread.)
Example usage (it shows that setting TZ doesn't affect UTC-timestamp):
$ TZ=GMT+3 java5 now_utc; TZ=GMT-3 java5 now_utc
now=2021-01-24 12:56:14 [unix ts=1611492974.264]
now=2021-01-24 12:56:14 [unix ts=1611492974.726]
I need to calculate a value that is based on dates. So I'm parsing the date first using date format class and then i'm using getTime() to get milliseconds. With those milliseconds i'll calculate some value. But getTime() is returning different values in different servers. We develop here in India, where i'm getting correct value but in US server i'm getting different value.
Scenario:
public class Test {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
String now = "11/03/2018";
Date UsualDateformat = sdf.parse(now);
System.out.println(UsualDateformat.getTime());
}
}
Above is a sample code, but my actual code is a rule in a drl file (drools).
This program returns
"1541183400000" which i convert to date is "Sat 3 November 2018 00:00:00".,
but in US server im getting "1541217600000" equal to date "Sat 3 November 2018 09:30:00".
So when i use this value i'm getting marginal decimal point formatting issue.
How to resolve this issue?
Thanks in advance!
You need to set the time zone on SimpleDateFormat to be consistent across servers in different regions. For example:
public class Test {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
....
}
}
You get these different values, because the time difference between your server in the US and the one in India is 9h 30.
This has nothing to do with floating points, but with time zones.
One way to solve this problem is to work always within the same time zone (e.g. India)
This code snippet might work for you,
public static String getGmtTime(String timezone) {
return ZonedDateTime
.now()
.withZoneSameInstant(ZoneId.of(timezone))
.toLocalDateTime()
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
pass timezone as America/Los_Angeles to get time with proper timezone,
Timezones can be found here
java.time
I recommend you use java.time, also known as JSR-310, for this. The classes you use, Date and SimpleDateFormat, are long outdated, and SimpleDateFormat in particular has a reputation for producing surprising results, which one may say also happened in your case. The modern API is generally so much nicer to work with.
As I think you have suspected already, your issue comes from the fact that your servers are running different time zones, and the conversion of a date to millis since the epoch is a time zone dependent operation since the epoch is always the same point in time (Jan 1 1970 at midnight in UTC). As mweiss I am using UTC for the conversion to make sure it gives the same result no matter the time zone of the server:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MM/dd/yyyy");
String now = "11/03/2018";
LocalDate date = LocalDate.parse(now, dtf);
long millisInUtc = date.atStartOfDay(ZoneOffset.UTC)
.toInstant()
.toEpochMilli();
System.out.println(millisInUtc);
As my code stands, it prints
1541203200000
This is between the values you got in India and US because UTC is between those two time zones. If you consider it more correct to use for example Asia/Kolkata time, simply substitute ZoneId.of("Asia/Kolkata") instead of ZoneOffset.UTC in the code, and you should get the same output as you already got when you ran your code on your server in India (please remember to rename the variable too).
My code is a bit longer than yours. I consider this an advantage in this case. Yes, indeed. The code using java.time is making explicit that we are using the time at the start of the day (0:00 midnight) and that we are using a time zone or offset for the conversion. This forces you as the coder to think about these issues, and you will be very unlikely to write code that produces results that differ unexpectedly across time zones, that is, your issue would never arise. At the same time it makes explicit to the reader that the operation depends on time zone, and that you have made a conscious choice of which zone to use. These advantageous are well worth a few more code lines.
I am saving time with other data to show in my app . I am storing the time in utc in db . Now when i run the program locally it works fine but when i run code on server the time is different from utc . My code to get utc timestamp is
private Timestamp getUTCTimestamp() throws ParseException
{
SimpleDateFormat sdf = new SimpleDateFormat(DATEFORMAT);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String utcTime = sdf.format(new Date());
SimpleDateFormat dateFormat = new SimpleDateFormat(DATEFORMAT);
Timestamp dateToReturn = new Timestamp(((Date)dateFormat.parse(utcTime)).getTime());
return dateToReturn;
}
It returns acurate utc time but when i run it on server it doesn't give the utc time e.g i ran the program locally and it gave me "2016-04-17 20:58:55" which was right and then after 10 mins i ran the code on server and it saved the time "2016-04-17 16:02:46" which was different .My server location is in netharlands. I don't understand , shouldn't the utc time be same everywhere??
Why are you formatting and then parsing the formatted string? Just use:
private Timestamp getUTCTimestamp() throws ParseException
{
return new Timestamp(new Date().getTime());
}
As to the issue you're seeing, I think #Stanislav Palatnik's comment is correct. You need to set the timezone on your format that is parsing the time string. Or just use the same format for formatting and parsing.. but again, why do you even need to go through that work?
If you are going to save current time on DB, it is much better to save with NOW() function of MySQL to make sure wherever the code runs, as far as the DB is the same, NOW() values will be consistent and you don't need to create time objects and lines of code to handle current time on java side.
see: https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_now
You are using old troublesome classes that are now outmoded. Avoid using SimpleDateFormat, java.util.Date/.Calendar and such, and minimize use of java.sql types.
Among their many problems is the behavior of toString method, applying a default time zone while generating the string. This confuses debugging efforts.
java.time
The java.time classes supplant the old date-time classes. Built into Java 8 and later, available as back-ports to Java 6 & 7 and to Android.
Do your business logic in java.time. Use java.sql only until JDBC drivers are updated to handle java.time types directly.
Define your column as something close to the SQL standard TIMESTAMP WITH TIME ZONE. Not "WITHOUT".
An Instant is a moment on the timeline in UTC.
Instant instant = Instant.now();
Convert to java.sql.Timestamp for storage in database.
java.sql.Timestamp ts = java.sql.Timestamp.from( instant );
Going the direction.
Instant instant = ts.toInstant();
The toString methods in java.time classes do not apply mysterious time zones when generating the textual representation of their date-time value. And they use standard ISO 8601 formats to further clarity.
So we go in and out of the database
all in UTC, no time zones, very simple, very clear.
When you need a wall-clock value such as far presentation to user, Apple a time zone to the instant to get a ZonedDateTime. Covered in detail in many other pages in Stack Overflow.
Your servers should be assigned a time zone of UTC (or Iceland). But never depend on that. Using the approach shown above makes the server’s time zone irrelevant.
No answer could have helped me because i found the reason and it had nothing to do with the code . I ran this command Date -u on putty and realized that the time isn't synchronized with utc and i don't know why . This post helped me in getting to this reason. I haven't tried the solution so if someone has a better solution feel free to tell me :) This is the
link
I have a requirement of getting UTC time , hence in many places iam using below code for calcualting utc time.
System.currentTimeMillis() ;
Iam in IST - (GMT+5:30) , System.currentTimeMillis() - should display UTC time (IST-5:30) , instead it is taking current time (GMT+5:30).
I donot want to use the Apache of joda date and time api. i want to use the Java api itslef. Help me in resolve my issue.
System.currentTimeMillis() just returns a long - that's not in any sort of date format.
If you're actually using:
Date date = new Date(System.currentTimeMillis());
System.out.println(date);
then you're just seeing the result of Date.toString(), which always uses the system default time zone.
Use DateFormat (e.g. SimpleDateFormat) to specify the calendar system (typically Gregorian), time zone and format you want to use. For example:
Date date = ...;
DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss",
Locale.US);
format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String result = format.format(date);
As an aside, I'd strongly recommend abstracting the idea of "getting the current time" into an interface which you implement in one case using System.currentTimeMillis() (or equivalently, just new Date()) but implement for testing purposes with a value you can set and update at will. Then inject this "clock" interface into anything which needs to access the current date/time. It makes it much easier to test time-based components.
(I'd also strongly recommend using Joda Time or the java.time package from Java 8 if you possibly can. I know you've said you don't want to, but I suspect that's because you haven't spent as much time swearing at java.util.Date and java.util.Calendar as some of us. Both of those alternatives will lead to much cleaner code which is much easier to read and reason about. If you're trying to avoid a one-time hit of getting Joda Time into your build process, weigh that against the amount of time you're likely to spend maintaining your code. Or just update to Java 8... Java 7 will be out of free-update support soon anyway...)
I'm using the following code to convert the time to local time. It was running 'on time' but today it jumped ahead by an hour.
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("EST"));
Using "ET" instead of "EST" doesn't work.
How can I correct the converted time?
Thanks!
You only show the code that creates the SimpleDateFormat, so apparently you are sure the problem is in there?
Debugging date/time/timezone/daylight savings related problems can be very difficult because it is very hard to 'see' the actual date; when you inspect it the Date's toString method will do some timezone conversion of it's own (based on current locale). So I find it most easy to convert all input to UTC and then print it out in UTC locale.
Anyway, you say 'ET' does not work? I have little experience with it, but if you look at the docs for TimeZone you should be able to come up with an algortithm o print out all timezones installed on your system. If EST differs from ET (does it?) then this will never work. You need to figure out the names Java has assigned to the ET timezone and use those to create the date formatter.
The trick is to parse the input (which is in locale X) using a date formatter for locale X and then use the Date (which is always in UTC, so timezone-neutral so to say) in your calculations. Then only go back to timezone X or Y for output by using a date format with the correct locale again.
You might try using EDT.
I know that seems totally counter to what you are trying to do here, but you might have a double adjustment somewhere if it sees EST and tries to convert to EDT.
The fact that daylight savings just hit today really points to the TimeZone issue.