How do I get java time millis in UTC ignoring the minutes and seconds.
For instance :
If it is October 10 2019, 1:10:59 AM , it should get the Time or millis for
October 10 2019, 1 AM.
Summary:
Instant
.now()
.truncatedTo(
ChronoUnit.HOURS
)
.toEpochMilli()
1570600800000
java.time, the modern Java date and time API has got exactly the method you need: many of the classes have a truncatedTo method for needs like yours.
Instant now = Instant.now();
System.out.println("Rough milliseconds: " + now.toEpochMilli());
Instant currentWholeHour = now.truncatedTo(ChronoUnit.HOURS);
System.out.println("Milliseconds ignoring minutes and seconds: "
+ currentWholeHour.toEpochMilli());
When running this snippet just now the output was:
Rough milliseconds: 1570604053787
Milliseconds ignoring minutes and seconds: 1570600800000
I know very well that the first line is what you asked not to have. I only included it for you to see the difference.
The truncation happens in UTC. If you are in a time zone whose offset is not a whole number of hours from UTC, the results may not be as you had expected. Examples of such time zones include Asia/Kathmandu, America/St_Johns some of the year also Australia/Lord_Howe.
Link: Oracle tutorial: Date Time
You can use LocalDate#atTime:
LocalDate.now().atTime(LocalDateTime.now().getHour(), 0, 0);
This will give you current date with hour and minutes and seconds set to 0.
And to get milliseconds in UTC:
LocalDate.now().atTime(LocalDateTime.now().getHour(), 0, 0).toInstant(ZoneOffset.UTC).toEpochMilli();
Jon Skeet notices, that calling now might give unexpected results in corner cases. To be sure, we can call it once and then convert it to LocalDate with mentioned solution:
var currentTime = LocalDateTime.now();
var currentDate = currentTime.toLocalDate();
Or the other way around - get LocalDate first and use LocalDate#atStartOfDay.
Given that you're interested in UTC milliseconds, and there are a whole number of milliseconds per hour, you can do this with simple arithmetic. For most calendrical computations I really wouldn't recommend that, but in this case I think it's the simplest approach. Something like this:
private static final long MILLISECONDS_PER_HOUR = TimeUnit.HOURS.toMillis(1);
// Injecting a clock makes the method testable. You can use Clock.systemUTC()
// for the system clock.
public static long truncateMillisToHour(Clock clock) {
long millisSinceEpoch = clock.millis();
// Truncate to the nearest hour
long hoursSinceEpoch = millisSinceEpoch / MILLISECONDS_PER_HOUR;
// Then multiply up again
return hoursSinceEpoch * MILLISECONDS_PER_HOUR;
}
Note that if the clock is for before the epoch, this will round up to the nearest hour, but if you're taking the genuine "current time" then that's unlikely to be a problem.
(I wrote this answer before seeing Ole V.V.'s answer with truncatedTo, which is a very nice approach.)
Related
From the front end I am receiving a separate LocalDate (variable name is date), along with separate Integers for hours, minutes, seconds, and an "AM" or "PM" String, and I need to combine these into a java.time.Instant object to store in the database. I tried to construct a LocalTime as follows, adding 12 hours if this is a PM time and then constructing an Instant:
LocalTime time = LocalTime.of("pm".equals(amPm) ? hours + 12: hours, minutes, seconds);
Instant instant = date.atTime(time).toInstant(ZoneOffset.UTC);
But when I store and reload the page, though the date is always intact, the time is always being changed. If I set the date to 1/29/1900 and the time to 07:01:01 AM, the Instant I am creating and storing has the value: 1900-01-29T07:01:01Z when I debug, which appears correct, but when the page reloads, the time says 02:01:01 AM, and that is the time that is stored in the database.
Am I constructing the time or the instant incorrectly?
There’s hardly any doubt that your unexpected observations are due to one or more time zone issues.
So the first thing you need to do is make sure you know which time zones are involved.
Which time zone is your front end using for sending date and time to you?
Which time zone is your database using for storing the date and time and displaying them to you when you check them? (UTC would be recommended for storing the times.)
Once you know this you can check:
Is the conversion from 1/29/1900 07:01:01 AM from the front end in some time zone to an Instant of 1900-01-29T07:01:01Z correct? The Instant displays its time in UTC (denoted by the trailing Z).
Is the conversion from the Instant to 02:01:01 AM in the database time zone correct?
Is the time being fetched correctly from the database? I am assuming you are fetching it back into Java?
Is the time you’ve got in Java being converted correctly to 02:01:01 AM on the front end? Again I am assuming that on page reload your are displaying the time fetched from the database, but I don’t think you have told us, so I could be wrong.
To answer your question:
Am I constructing the time or the instant incorrectly?
It depends; it’s certainly possible.
Your construction of the time is assuming that pm is always in lower case and that 12 o’clock (midnight or noon) is given as 0. On one hand I find both assumptions more or less unlikely, on the other hand they cannot account for the discrepancy of 5 hours that you observed. 12 would conventionally be given as 12 (not 0) on a 12 hour clock. And your question gives PM in upper case.
Your construction of the Instant assumes that the front end sent the time in UTC. To me this sounds unlikely too, and it may be the reason or one of the reasons why you observed an incorrect time being displayed back after page reoload.
Code example
In the following snippet I am making the opposite assumptions: 12 is given as 12, AM/PM may be in any case, and the front end time zone is America/New_York. It’s probably way off, but there may be a detail that you can pick and use for your purpose.
DateTimeFormatter timeFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive() // Accept all of am, AM, aM and Am
.appendPattern("h:m:sa")
.toFormatter(Locale.US);
ZoneId zone = ZoneId.of("America/New_York");
LocalDate date = LocalDate.of(1900, Month.JANUARY, 29);
int hours = 7;
int minutes = 1;
int seconds = 1;
String amPm = "AM";
String constructedTimeString
= "" + hours + ':' + minutes + ':' + seconds + amPm;
LocalTime time = LocalTime.parse(constructedTimeString, timeFormatter);
Instant instant = date.atTime(time).atZone(zone).toInstant();
System.out.println(instant);
Output is:
1900-01-29T12:01:01Z
Geeky section: avoiding formatting time into a string and parsing it back
I couldn’t help thinking about whether it would be possible to have java.time parse the AM/PM string without having to construct a string for the time of day and parse it. It is possible, but we need to use the low-level TemporalAccessor interface, which is otherwise usually unnecessary.
DateTimeFormatter amPmFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive() // Accept all of am, AM, aM and Am
.appendPattern("a")
.toFormatter(Locale.US);
int hours = 7;
int minutes = 1;
int seconds = 1;
String amPm = "AM";
TemporalAccessor parsedAmPm = amPmFormatter.parse(amPm);
LocalTime time = LocalTime.of(0, minutes, seconds)
.with(ChronoField.AMPM_OF_DAY, parsedAmPm.get(ChronoField.AMPM_OF_DAY))
.with(ChronoField.CLOCK_HOUR_OF_AMPM, hours);
System.out.println(time);
07:01:01
Construction of the Instant proceeds as before.
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.
just to verify this: I have this lame and brain dead method to calculate the time zone offset for my current location. I wonder if I need to adjust it when Day Light Saving time comes into question (currently we have Winter Time at my location, CET time zone, so it's hard to verify).
// The local time zone's offset
private int getLocalOffset() {
DateTimeZone defaultZone = DateTimeZone.getDefault();
return defaultZone.getOffset(null) / 1000 / 60 / 60;
}
Thanks for any hint.
Time zones and Daylight Saving Time are a nightmare. You certainly shouldn't take on this task yourself. Let Joda-Time do the heavy lifting.
See this answer to similar question, Using Joda time to get UTC offset for a given date and timezone. The class DateTimeZone offers a getOffset() method.
Example source code in Joda-Time 2.3 in Java 7…
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
org.joda.time.DateTimeZone californiaTimeZone = org.joda.time.DateTimeZone.forID("America/Los_Angeles");
org.joda.time.DateTime now = new org.joda.time.DateTime(californiaTimeZone);
int millisecondOffsetToAddToUtcToGetLocalTime = californiaTimeZone.getOffset( now );
System.out.println( "millisecondOffsetToAddToUtcToGetLocalTime: " + millisecondOffsetToAddToUtcToGetLocalTime );
// Note the casting to doubles to avoid integer truncation. Time zone offsets are NOT always whole hours.
System.out.println( "Offset in decimal hours: " + (double)millisecondOffsetToAddToUtcToGetLocalTime / 1000d / 60d / 60d );
When run at 2013-11-20T01:03:56.464-08:00…
millisecondOffsetToAddToUtcToGetLocalTime: -28800000
millisecondOffsetToAddToUtcToGetLocalTime in hours: -8.0
IMPORTANT That number format -8.0 is incorrect for an offset. Must be either:
-08:00 with the colon and double digits (padded with leading zero).
-08 with leading zero.
Normally, Joda time will take care of DST by itself, so you don't have to worry about it. However, I notice that you are passing null to getOffset(). Given that the time zone offset depends on the date, you really should be passing the date/time at which you are calculating the offset, or you're going to get wrong results.
Also as mentionned in my previous comment: Be aware that some timezones have an offset that isn't a whole number of hours. India for example is at GMT +5:30
Yes, that's fine. To verify that it is correct - instead of passing null pass in a DateTime object to DateTimeZone.getOffset - set the datetime to sometime in summer when you know DST is in effect - you should see the offset value change.
What is the proper way to turn an integer of seconds into a formatted string of hh:mm:ss in Java?
For instance:
int Seconds = 650
String Time = 00:10:50
Right now I'm using this:
String Time = new SimpleDateFormat("hh:mm:ss").format(new Date((Seconds*1000)));
But this seems to tack on hours for no reason, and I'm guessing it's because I'm misusing Date or SimpleDateFormat, but I'm too inexperienced to know what's wrong. Or is there just a built in system for this that I don't know about.
EDIT: I should point out that I know I could use simple division to peel out the hours, then the remaining minutes, then the remaining seconds, and patch all three of those pieces into a string, but I was wondering if Java has a baked-in way to do this.
You can use TimeUnit class defined in java.util.concurrent package.
for eg you want to calculate hours:
long hours=TimeUnit.SECONDS.toHours(seconds);
similar methods are available for calulating days, hours, minutes.
but mind you this will give you direct conversion to hours, so you will end up having more than 24 hours. For a proper implementation you need to first calculate the days, the do the necessary maths and the give the remaining value for calculating hours. Lastly write a string as per your required format.
There is actually a (good) reason "to tack on hours".
Date(long date) constructor's JavaDoc:
Allocates a Date object and initializes it to represent the specified number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.
So, if your JVM is not running in the GMT timezone you're off accordingly.
It's by design and logical, too:
new Date() is expected to be your current local time
new Date(0) is expected to be January 1, 1970, 00:00:00 GMT + local offset = local time
new Date(650*1000) is expected to be January 1, 1970, 00:10:50 GMT + local offset = local time
Try it the following way,
int seconds = 650;
long millis = seconds * 1000;
String format = String.format("%d:%d:%d",
TimeUnit.MILLISECONDS.toHours(millis),
TimeUnit.MILLISECONDS.toMinutes(millis),
TimeUnit.MILLISECONDS.toSeconds(millis)
- TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
);
System.out.println(format);
your code is correct .but problem is this gives you the time relative to start position .think if you run following code
String Time = new SimpleDateFormat("EEEE,MMMM d,yyyy hh:mm,a").format(new Date((0)));
System.out.println(Time);
output>>Wednesday,December 31,1969 04:00,PM //this 04 will be reason to your undesired output later
i think that is the minimum time for positive seconds .think when you give milliseconds 0 java gives you day as Wednesday and 4 hours ,so starting hours of java time is not 0.
so when you run
following code
String Time = new SimpleDateFormat("hh:mm:ss").format(new Date((Seconds*1000)));
output>> 04:10:50 //you expect 00:10:50
because `starting time+seconds`
04:00:00 + 00:10:50
but starting minutes and seconds are 0 so you only have problem about hours
if you can subtract starting hours then you will get desired output.
joda time library has interval so you can use it .take a look at this question
I'm going to design an application, in which I need to get the exact time difference between two dates. Ex:
Date1:31/05/2011 12:54:00
Date2:31/05/2011 13:54:00
I tried using getTime() but I didn't get exact result.
The expected output for the above inputs is 3600000 (60 * 60 * 1000) millisec but I'm getting 46800000 (13 * 60 * 60 * 1000).
When I went through different java forums people are suggesting to use JodaTime.
Still I'm unable to get the exact result.
The timezone on I'm working is London(GMT).
Init two dateTime and use Period :
DateTime dt1 = new DateTime(2013,9,11,9,58,56);
DateTime dt2 = new DateTime(2013,9,11,9,58,59);
Period p = new Period(dt1, dt2, PeriodType.millis());
To get difference in milliseconds :
System.out.println(p.getValue(0));
public static long getDiff(Calender cal1, Calender cal2)
{
return Math.abs(cal1.getTimeInMillis() - cal2.getTimeInMillis());
}
Check out secondsBetween( )
Creates a Seconds representing the number of whole seconds between the
two specified partial datetimes.
The two partials must contain the same fields, for example you can
specify two LocalTime objects.
Parameters:
start - the start partial date, must not be null
end - the end partial date, must not be null
Returns:
the period in seconds
JodaTime is using machine time inside. So to find miliseconds, you can use a constant storing LocalDateTime referring to Jan 1, 1970(Because of UNIX Time).
Unix time, or POSIX time, is a system for describing points in time,
defined as the number of seconds elapsed since midnight proleptic
Coordinated Universal Time (UTC) of January 1, 1970, not counting leap
seconds. Then calculate the difference between your DateTime.
I tried like this;
public static void main(String[] args) {
final LocalDateTime JAN_1_1970 = new LocalDateTime(1970, 1, 1, 0, 0);
DateTime local = new DateTime().withZone(DateTimeZone.forID("Europe/Amsterdam"));
DateTime utc = new DateTime(DateTimeZone.UTC);
System.out.println("Europe/Amsterdam milis :" + new Duration(JAN_1_1970.toDateTime(DateTimeZone.forID("Europe/Amsterdam")), local).getMillis());
System.out.println("UTC milis :" + new Duration(JAN_1_1970.toDateTime(DateTimeZone.UTC), utc).getMillis());
}
And the result is;
Europe/Amsterdam milis :1429695646528
UTC milis :1429692046534
And #leonbloy write here a good comment.
Your local and utc represent the same instants of time, (only with
different timezones attached). Hence, getMillis() (which gives the
"physical" time interval elapsed from the "instant" corresponding to
the unix epoch), must return the same value.
Joda is a perfect library but if you need the difference between 2 dates in milliseconds you just should calculate difference between getTime(). If you get wrong results you have some problems with timezones or so. Typically it works.