does System.currentTimeMillis() return UTC time? - java

I want to get the current UTC time in millis. I searched google and got some answers that System.currentTimeMillis() does returns UTC time. but it does not. If I do following:
long t1 = System.currentTimeMillis();
long t2 = new Date().getTime();
long t3 = Calendar.getInstance().getTimeInMillis();
all three times are almost same ( difference is in milli seconds due to calls ).
t1 = 1372060916
t2 = 1372060917
t3 = 1372060918
and this time is not the UTC time instead this is my timezone time. How can i get the current UTC time in android?

All three of the lines you've shown will give the number of milliseconds since the unix epoch, which is a fixed point in time, not affected by your local time zone.
You say "this time is not the UTC time" - I suspect you've actually diagnosed that incorrectly. I would suggest using epochconverter.com for this. For example, in your example:
1372060916 = Mon, 24 Jun 2013 08:01:56 GMT
We don't know when you generated that value, but unless it was actually at 8:01am UTC, it's a problem with your system clock.
Neither System.currentTimeMillis nor the value within a Date itself are affected by time zone. However, you should be aware that Date.toString() does use the local time zone, which misleads many developers into thinking that a Date is inherently associated with a time zone - it's not, it's just an instant in time, without an associated time zone or even calendar system.

I can confirm that all three calls could depend on the local time, considering the epoch, not the Date.toString() or any similar method. I've seen them depend on local time in specific devices running Android 2.3. I haven't tested them with other devices and android versions. In this case, the local time was set manually.
The only reliable way to get an independent UTC time is requesting a location update using the GPS_PROVIDER. The getTime() value of a location retrieved from NETWORK_PROVIDER also depends on local time. Another option is ping a server that returns a UTC timestamp, for example.
So, what I do is the following:
public static String getUTCstring(Location location) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(location.getTime()));
// Append the string "UTC" to the date
if(!date.contains("UTC")) {
date += " UTC";
}
return date;
}

Related

Simple date format giving wrong time

I have a time in milliseconds: 1618274313.
When I convert it to time using this website: https://www.epochconverter.com/, I am getting 6:08:33 AM.
But when I use SimpleDateFormat, I am getting something different:
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
System.out.println(sdf.format(new Date(1618274313)));
I am getting output as 23:01:14.
What is the issue in my code?
In your example, you are using time 1618274313 and you are assuming that it is in milliseconds. However, when I entered the same time on https://www.epochconverter.com/, I got below results:
Please notice the site mentions: Assuming that this timestamp is in seconds.
Now if we use that number multiplied by 1000 (1618274313000) as the input so that the site considers it in milliseconds, we get below results:
Please notice the site now mentions: Assuming that this timestamp is in milliseconds.
Now, when you will use 1618274313000 (correct time in milliseconds) in Java with SimpleDateFormat, you should get your expected result (instead of 23:01:14):
SimpleDateFormat sdf=new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
System.out.println(sdf.format(new Date(1618274313000)));
use Instant.ofEpochSecond
long test_timestamp = 1618274313L;
LocalDateTime triggerTime =
LocalDateTime.ofInstant(Instant.ofEpochSecond(test_timestamp),
TimeZone.getDefault().toZoneId());
System.out.println(triggerTime);
it prints output as 2021-04-13T06:08:33
Assuming it is in milliseconds as you say, all you know for certain is that you have a specific duration.
Duration d = Duration.ofMillis(1618274313);
System.out.println(d);
Prints
PT449H31M14.313S
Which says it is 449 hours, 31 minutes and 14.313 seconds of duration. Without knowing the epoch of this duration and any applicable zone offsets, it is not really possible to ascertain the specific date/time it represents. I could make lots of assumptions and provide results based on that, but more information from you would be helpful.
java.time
As Viral Lalakia already spotted, the epoch converter that you linked to, explicitly said that it assumed that the number was seconds (not milliseconds) since the epoch. The following makes the same assumption in Java. I recommend that you use java.time, the modern Java date and time API.
ZoneId zone = ZoneId.of("Asia/Kolkata");
long unixTimestamp = 1_618_274_313;
Instant when = Instant.ofEpochSecond(unixTimestamp);
ZonedDateTime dateTime = when.atZone(zone);
System.out.println(dateTime);
System.out.println(dateTime.format(DateTimeFormatter.ISO_LOCAL_TIME));
Output is:
2021-04-13T06:08:33+05:30[Asia/Kolkata]
06:08:33
This agrees with the 6:08:33 AM that you got from the converter. And the date is today’s date. A coincidence?
If the number is indeed milliseconds (which I honestly doubt), just use Instant.ofEpochMill() instead of Instant.ofEpochSecond().
Instant when = Instant.ofEpochMilli(unixTimestamp);
1970-01-19T23:01:14.313+05:30[Asia/Kolkata]
23:01:14.313
This in turn agrees with the result you got in Java (except that the milliseconds are also printed).

Can't get local and utc Instant

I need to get local time and utc time in seconds. I read some posts in StackOverflow and found some solution, which is correct as mentioned:
Instant time = Instant.now();
OffsetDateTime utc = time.atOffset(ZoneOffset.UTC);
int utcTime = (int) utc.toEpochSecond();
int localTime = (int) time.getEpochSecond();
System.out.println("utc " + utcTime + " local " + localTime);
But result is not what I expected. It is utc time. The output:
utc 1593762925
local 1593762925
After debugging I found that Instant.now() is already utc. I can't find how to get time in current time zone, i.e. my system zone.
I found some solution in API but got error:
OffsetDateTime utc = time.atOffset(ZoneOffset.of(ZoneOffset.systemDefault().getId()));
Exception in thread "main" java.time.DateTimeException: Invalid ID for ZoneOffset, invalid format: Europe/Astrakhan
at java.base/java.time.ZoneOffset.of(ZoneOffset.java:241)
UPD: My question is How to get current time in seconds in local time zone and in UTC? I.e. the number of seconds since 1970-01-01T00:00:00 GMT+4 and 1970-01-01T00:00:00 GMT+0
UPD2: I have some device that needs response with utc time in seconds from 1970 and sender local time in seconds. Why? I don't know. It is black box for me.
I think you need to take the Instant, create a ZonedDateTime (OffsetDateTime may be suitable as well) by applying a ZoneId.of("UTC") and then take that ZonedDateTime and use it to shift the locale:
public static void main(String[] args) {
Instant now = Instant.now();
ZonedDateTime utcZdt = now.atZone(ZoneId.of("UTC"));
ZonedDateTime localZdt = utcZdt.withZoneSameLocal(ZoneId.systemDefault());
System.out.println(utcZdt.toEpochSecond() + " <== " + utcZdt);
System.out.println(localZdt.toEpochSecond() + " <== " + localZdt);
}
On my system, this outputs
1593765852 <== 2020-07-03T08:44:12.070Z[UTC]
1593758652 <== 2020-07-03T08:44:12.070+02:00[Europe/Berlin]
Two hours difference are affecting the sixth digit of the epoch seconds.
Found solution here:
TimeZone tz = TimeZone.getDefault();
Instant instant = Instant.now();
int offsetFromUtc = tz.getOffset(instant.getEpochSecond()) / 1000;
Or as wrote #deHaar:
int offsetFromUtc = Instant.now().atZone(ZoneOffset.systemDefault()).getOffset().getTotalSeconds();
It gives 14400 s that is correct for my timezone. I can add this to utc.
TL;DR: Your expectations are wrong. Your results are correct.
The results you are getting is the count of seconds since the Unix/Java epoch. This is also known as a Unix timestamp. The epoch is one point in time and is independent of time zone. It’s the same point in time in all time zones. Therefore the count of seconds is the same in all time zones too.
The epoch is 1970-01-01T00:00:00 GMT+0. In some time zones (yours?) this point in time would be given as 1970-01-01T04:00:00 GMT+4. Please note the time of day is 4 AM, not 00:00.
In case someone else was wrong
UPD2: I have some device that needs response with utc time in seconds
from 1970 and sender local time in seconds. Why? I don't know. It is
black box for me.
It’s a possibility, of course, that the designers of that device misunderstood and probably inadvertently invented their own way of counting seconds. It doesn’t sound very likely, though, so I would at least double-check and triple-check this piece of information. If it turns out to be correct, I would do something like:
LocalDateTime misunderstoodEpoch = LocalDate.EPOCH.atStartOfDay();
ZoneId zone = ZoneId.of("Europe/Astrakhan");
long secondsLong = ChronoUnit.SECONDS
.between(misunderstoodEpoch.atZone(zone), ZonedDateTime.now(zone));
int seconds = Math.toIntExact(secondsLong);
System.out.println(seconds);
Output when running just now:
1593881344
Also if your device insists on using an int for your seconds, at least use Math.toIntExact() for the conversion. This will throw an exception in case of int overflow so that in January 2038 (just 17 years 6 months from now) you and your users will be made aware of the fact that your device is no longer working.

How to set a date in certain timezone? [duplicate]

This question already has answers here:
How to set time zone of a java.util.Date?
(12 answers)
Closed 5 years ago.
I am using timer to perform certain tasks in certain period. This method requires Date type if you want to make the task start from that date and repeat in every period.
I have been trying to find solution for this for hours but couldn't come up with anything. I create calendar and set a timezone for it. Then when I get date from that calendar this date contains my LOCAL TIME. I tried getting string from Date using SimpleDataFormat and it worked because you set timezone for SimpleDataFormat separately. Then even tried parsing that string into the date but it still didn't work. I'm kinda hopeless at this moment. What's the point of setting timezone for calendar if I'm not able to use it. I could still do something if it wasn't getting my local time but instead it was getting UTC. But that's not the case either. I don't want to make this application run based on the computer's local time. That's absurd it should be able to get local time and turn it into the time zone I want and use it like that.
Code:
TimeZone eu = TimeZone.getTimeZone("GMT+1");
TimeZone america = TimeZone.getTimeZone("EST");
TimeZone asia = TimeZone.getTimeZone("GMT+7");
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
df.setTimeZone(eu);
Calendar euCal = Calendar.getInstance(eu);
Date dateEu = euCal.getTime();
System.out.println(dateEu); //Prints local time date
euCal.setTimeZone(eu);
System.out.println(dateEu); //Still prints local time date
String formattedDateEu = df.format(dateEu);
System.out.println(formattedDateEu); //This one works fine but it is string
try {
dateEu = df.parse(formattedDateEu);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(dateEu); //Fun part. Although I don't get exception dateEu is still not in the time zone I want.
Sample Output:
Mon Nov 27 14:37:21 MSK 2017
Mon Nov 27 14:37:21 MSK 2017
27/11/2017 12:37:21
Mon Nov 27 14:37:21 MSK 2017
java.util.Date objects don't contain time zone information. They represent an instant in the time continuum that is the same instant for everyone regardless of whether they so happen to be in Paris or New York at the moment.
However, when you try to print a Date object with System.out.println() it needs to try and describe itself. So it will need to describe the date and time it represents, but to do that it first needs to choose a time zone to represent this date and time in, since it doesn't have one. For convenience it chooses the user's system time zone.
You're not going to use your Date by calling System.out.println() with it, so you shouldn't care what System.out.println() does with it.
I wish I could tell you to stay away from the long outdated Date class. Today we have so much better in java.time, the modern Java date and time API. However, you are correct that java.util.Timer does need a Date for scheduling a task at a specific date and time. Still, since the modern API is so much nicer to work with, I recommend you use it for initializing your Date:
ZoneOffset eu = ZoneOffset.ofHours(1);
ZoneOffset america = ZoneOffset.ofHours(-5);
ZoneOffset asia = ZoneOffset.ofHours(7);
OffsetDateTime euTime = OffsetDateTime.now(eu);
System.out.println(euTime);
Date dateEu = Date.from(euTime.toInstant());
// schedule to start at the specified date-time and repeat weekly
myJavaUtilTimer.scheduleAtFixedRate(myTask, dateEu, TimeUnit.DAYS.toMillis(7));
I appears to me you aren’t really using time zones, just offsets from GMT (or UTC). So I put in some ZoneOffsets in the code. The result of printing euTime just now was
2017-11-27T15:56:03.213+01:00
You can see that the offset is +01:00 as expected. Then, as kumesana already said in the other answer, don’t print the resulting Date, just trust that it’s OK.
If you do prefer real time zones, use for example:
ZoneId eu = ZoneId.of("Europe/Brussels");
ZoneId america = ZoneId.of("America/Jamaica");
ZoneId asia = ZoneId.of("Asia/Krasnoyarsk");
The rest of the code is the same. That’s true: OffsetDateTime.now() accepts either a ZoneOffset or a ZoneId, so you can even mix both types. Of the above time zones, Europe/Brussels uses summer time (DST), so you will get an offset of +02:00 during 7 months of the year.
Avoid the three letter time zone abbreviations like EST. They are often ambiguous. Do prefer to specify your time zones in the region/city format as I do in my code.
EDIT: Here’s an example run from my computer:
2017-11-28T19:04:22.917+01:00
myTask running # 2017-11-28T19:04:23.156+01:00[Europe/Oslo]
As you can see, myTask ran 239 milliseconds after the specified firstTime for the scheduled task. Such latency should be expected. In a second run, the difference was down to 130 ms.

How do I set a joda LocalDateTime object to a specified time with current and local daylight savings and time zone information in java

I'm trying to create a java.sql.Time object to query time types in an SQL database, but I'm using joda to parse the string that I receive.
I've tried a few different approaches. This is my most recent.
protected Time startTime = null;
protected static final String dateFormat = "HH:mm:ssZ";
protected static final DateTimeFormatter formatter = DateTimeFormat.forPattern(dateFormat);
public TimeBetweenFilter(String fieldName, String type, String value) {
super(fieldName, type, value);
String [] times = value.split("\\|");
if(times.length == 2 && !times[0].isEmpty() && !times[1].isEmpty()){
try{
LocalDateTime current = LocalDateTime.now();
LocalDateTime timeFromEpoch= new LocalDateTime(formatter.parseDateTime(times[0]));
startTime = new Time(timeFromEpoch.withDate(current.getYear(), current.getMonthOfYear(), current.getDayOfMonth()).toLocalTime().toDateTimeToday().getMillis());
}catch (Exception e){
...
}
But the output is always 1 hour behind the input received. For instance, if the input is 10:30:00 in UTC, startTime should be 4:30:00 local time. But instead I get 3:30.
Solved
DateTime beginning = new DateTime(DateTimeZone.UTC).toDateMidnight().toDateTime().plus(DateTime.parse(times[0], formatter).getMillis());
startTime = new Time(beginning.getMillis());
Creates a new date, this morning at midnight with time zone UTC, then adds the UTC time of day in milliseconds. Then it's converted to a java.sql.Time object.
A LocalDateTime doesn't logically have any time zone or DST information. That's the whole point - it's "local" but not to any specific time zone. Two people in different time zones might both wake up at the same local date/time, but that doesn't mean they're the same instants.
If you need a type which includes a time zone, you should be using DateTime.
EDIT: Okay, one approach is to take "today in the local time zone", parse the time to a LocalTime, combine the two to form a LocalDateTime, convert that to a DateTime in UTC, then convert that DateTime to the local time zone instead. The difficulty is that the end dates may not be the same, in which case you may need to add or subtract a day. That could then change the time of day due to DST changes, which makes it harder still. There are likely to be nasty corner cases to consider.
It feels like your requirement is odd to start with though - it's odd to have just a time which is in UTC, which you want to use in a date/time in the local time zone. Perhaps if you gave some more context, that would help.

Android: Time stored in db is not the same as on phone

I'm using System.currentTimeMillis(); to get the current time for my 'modified' db field. I'm converting it to unix epoch by dividing it by 1000.
However, even when the phone's / emulator's date and time are set to true time, the value stored in the db is 2 hours earlier than true time.
I'm in GMT+2, but I can't find how this is affecting.
Doesn't System.currentTimeMillis(); get the current time for the current time settings ?
use Calendar.getInstance() instead, as this:
Calendar curTime = Calendar.getInstance();
This curTime object will be locale-specific.
From the API, in regards to currentTimeMillis()
This method shouldn't be used for measuring timeouts or other elapsed time measurements, as changing the system time can affect the results.
currentTimeMillis doesn't return timezone-dependent timestamps:
the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
However, it is good practice to store timestamps in UTC and to not include timezone offsets. To display the "correct" time, you can use a SimpleDateFormat:
SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
// set your Timezone; or use TimeZone.getDefault() for the device timezone
df.setTimeZone(TimeZone.getTimeZone("Europe/Paris"));
String time = df.format(new Date(timestamp));
From the documentation:
"returns the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC"
It gives you the time, independant from your time zone. So you should calculate the correct time yourself.

Categories