Epoch time in Java - java

I would like to represent 1 day from current date as epoch time. Today's date is Oct 20th. So I would like to get the epoch time for tomorrow. I have the below code -
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.DAY_OF_YEAR, 1);
int time = (int) ((cal.getTimeInMillis())/1000);
System.out.println("TIME IS: " +time);
So I basically want to add 1 day to current day of the year i.e. Oct 20th, and represent that as epoch time. I am displaying the time in seconds, hence the divide by 1000. The result for the program is 1413958770. 1 day from today would be 86400 seconds. How exactly does epoch time work? I understand it gives time since 1970, but if that is indeed the case, the value can't be that small :-). Am I missing something here?

Let's do some basic math:
a minute has 60 seconds
an hour has 60 minutes
a day has 24 hours
a year has 365 days
1413958770 / (60 * 60 * 365 * 24) = 44,8
(test it)
Add 44,8 years to 1970, and you'll be in 2014. So nothing is wrong.

If "today" is the epoch, then it should "represent" 0, any time measured from or compared to "now" should be subtracted from it, for example...
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
long now = cal.getTimeInMillis();
cal.add(Calendar.DAY_OF_YEAR, 1);
long then = cal.getTimeInMillis();
long secondsFromEpoch = (then - now) / 1000;
System.out.println(secondsFromEpoch);

Unix time or POSIX time or Epoch time is a system for describing instants in time, defined as the number of seconds that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, not counting leap seconds.
In Java, you can simply get it using below statement.
long current_time = System.currentTimeMillis() * 1000000L;
or
long epoch = date.getTime();

There have been a couple dozen epochs used by various computer systems. The beginning of 1970 UTC is common, but certainly not the only epoch in current use. And various systems track time since epoch using whole seconds, milliseconds, microseconds, and nanoseconds. So rather than use the vague term "epoch time", it would be more useful to directly say what you want. In this case it seems to be "whole seconds since beginning of 1970 UTC until tomorrow".
Perhaps you were just curious about the math and numbers. But if you were serious about the date-time work, then I advise using the Joda-Time library or the java.time package in Java 8.
Time zone is crucial when taking about dates and defining the beginning of a day.
Here is example code using Joda-Time 2.5.
DateTimeZone zone = DateTimeZone.forID( "Australia/Melbourne" );
DateTime tomorrowStart = DateTime.now( zone ).plusDays( 1 ).withTimeAtStartOfDay();
long secondsSinceUnixEpoch = ( tomorrowStart.getMillis() / 1000 );

Related

Java Calendar not giving end of hour

Based on Epoch seconds, I convert it to the start of hour and end of hour.
long epochSeconds = 1589374800L;
Instant instant = Instant.ofEpochSecond(epochSeconds);
Calendar now = Calendar.getInstance(TimeZone.getTimeZone(ZoneId.of("Asia/Kolkata")));
now.setTimeInMillis(instant.toEpochMilli());
System.out.println(now.getTime()); // Correct --> Wed May 13 06:00:00 PDT 2020
Calendar endOfHour = (Calendar)now.clone();
endOfHour.set(Calendar.MINUTE, 59);
endOfHour.set(Calendar.SECOND, 59);
endOfHour.set(Calendar.MILLISECOND, 999);
System.out.println(endOfHour.getTime()); // Wrong ---> Wed May 13 06:29:59 PDT 2020
The start of hour seems correct, but the end of hour is not giving it right, instead of upto 59 minute, 59 second, 999 millisecond it is giving only half hour difference.
You are mixing java.time and java.util.Calendar types. Don't do that. For one thing, you're losing the TimeZone you specified when you clone. Basically, Calendar is a mess. But you don't need it here, something like
long epochSeconds = 1589374800L;
LocalDateTime date = Instant.ofEpochSecond(epochSeconds) //
.atZone(ZoneId.of("Asia/Kolkata")) //
.toLocalDateTime();
System.out.println(date);
LocalDateTime endOfHour = date.withMinute(59) //
.withSecond(59) //
.with(ChronoField.MILLI_OF_SECOND, 999);
System.out.println(endOfHour);
Should meet your needs. Here that outputs
2020-05-13T18:30
2020-05-13T18:59:59.999
Two points (and one more at the end):
Just repeating what has already been said: don’t mix old and modern date-time classes. Use the modern ones exclusively. Forget about the old ones. They were always poorly designed anyway.
Your observed result is correct and as should be expected.
You are using Asia/Kolkata time zone for your (outmoded) Calendar object. Asia/Kolkata time zone is special in that it is not offset a whole number of hours from UTC as most time zones are, but +05:30, five and a half hours. Let’s look at your times in this time zone first. Your epoch second value (AKA Unix timestamp) is equal to 2020-05-13T18:30:00+05:30 in Asia/Kolkata. The end of that hour in Asia/Kolkata is 2020-05-13T18:59:59.999. This is the result that you get.
It seems that you are running your program on a JVM in a different time zone (perhaps America/Vancouver or America/Los_Angeles). This time zone is offset a whole number of hours from UTC, so 18:59:59.999 in India equals 06:29:59 PDT (your time zone).
Half-open:
I promised you a third point. Represent the end of the hour as the whole hour, here 19:00 rather than 18:59:59 and some number of 9s. The philosophical argument: The hour doesn’t end one millisecond before the next hour begins, so this is incorrect. The practical argument: It frees you from deciding how many 9s you need. java.time has nanosecond precision, so is able to represent nearly a million points in time between your end of the hour and the beginning of the next hour. You risk hitting such a point and assigning it to the wrong hour. In comparisons just make sure that you are checking whether a point in time is strictly before the whole hour where the hour ends.
If you do need Calendar objects for a legacy API:
ZoneId zone = ZoneId.of("Asia/Kolkata");
long epochSeconds = 1589374800L;
ZonedDateTime now = Instant.ofEpochSecond(epochSeconds).atZone(zone);
Calendar nowAsOldfashionedCalendar = GregorianCalendar.from(now);
ZonedDateTime endOfHour
= now.plusHours(1).truncatedTo(ChronoUnit.HOURS).minusNanos(1);
Calendar endOfHourAsOldfashionedCalendar = GregorianCalendar.from(endOfHour);
I included .minusNanos(1) to get the last nanosecond of the previous hour, but as I said, you should prefer to omit it if you can. The conversion to GregorianCalendar will truncate to milliseconds and give you the same result as in your code in the question.

Java millis time with hourly resolution

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.)

Calendar.add changes time zone

In the following code, range equals durationInDays only when range is less than 30. If it is equal to 30 or greater, durationInDays is always range - 1
Calendar c = Calendar.getInstance();
Date now = new Date();
c.setTime(now);
int range = 35;
c.add(Calendar.DATE, range);
Date then = c.getTime();
Duration duration = Duration.between(now.toInstant(), then.toInstant());
int durationInDays = (int)duration.toDays();
When debugging this example, the variables are set as follows:
this = {CalTest#871}
c = {GregorianCalendar#876} "java.util.GregorianCalendar[time=1522449516301,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Dublin",offset=0,dstSavings=3600000,useDaylight=true,transitions=228,lastRule=java.util.SimpleTimeZone[id=Europe/Dublin,offset=0,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2018,MONTH=2,WEEK_OF_YEAR=13,WEEK_OF_MONTH=5,DAY_OF_MONTH=30,DAY_OF_YEAR=89,DAY_OF_WEEK=6,DAY_OF_WEEK_IN_MONTH=5,AM_PM=1,HOUR=11,HOUR_OF_DAY=23,MINUTE=38,SECOND=36,MILLISECOND=301,ZONE_OFFSET=0,DST_OFFSET=3600000]"
now = {Date#877} "Fri Feb 23 23:38:36 GMT 2018"
range = 35
then = {Date#878} "Fri Mar 30 23:38:36 IST 2018"
duration = {Duration#879} "PT839H"
durationInDays = 34
Why does then have an IST timezone? This difference is the causing duration to be a little less than 35 days, rounding to 34.
First, then hasn’t got IST timezone. A Date hasn’t got any time zone. Date.toString chooses a time zone, usually the JVM’s time zone setting, for generating the string only.
Looking at how your two Date objects are rendered in the debugger, one might wonder that it would appear they are rendered in two different time zones. They are not. Both are in Europe/Dublin time zone. As you are probably aware, Ireland with most of the EU switches to summer time (DST) on the last Sunday in March. Therefore, your date in February is in standard time, which in Ireland coincides with GMT, and therefore your string is rendered with GMT as “time zone”. On March 30, summer time is in effect, so the time zone is rendered as IST for Irish Summer Time this time. Edit: the transistion to summer time also accounts for the missing hour compared to your expected duration of 35 days (840 hours).
Edit: Since you can use java.time, the modern Java date and time API, I suggest you go all in and forget about the old-fashioned Date and Calendar. The modern API is so much nicer to work with, and you won’t need all the conversions any longer:
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Europe/Dublin"));
int range = 35;
ZonedDateTime then = now.plusDays(range);
Duration duration = Duration.between(now, then);
int durationInDays = (int) duration.toDays();
The result is still PT839H and hence 34 days.
To obtain a duration in days that agrees with the number of days we added:
int durationInDays = (int) ChronoUnit.DAYS.between(now, then);
System.out.println(durationInDays);
This prints
35
Duration is mostly for durations in hours, minutes and seconds. It does support days, but only days at 24 hours each, so gives the surprising result you saw when used across the summer time transition. ChronoUnit.DAYS on the other hand is exactly made for days. It sees that the two ZonedDateTime instances have the same time-of-day and therefore acknowledges a full 35 days between the two.

Get current time of day in seconds

Is there a way to get the current time of the day in seconds? Notice I am asking the time of the day, not UTC time.
What I want is a value (in seconds) between the range 0 - 86,400 (12:00AM - 11:59PM). I'm working on an app that works on a daily basis, and when the day ends, the time (in seconds) should restart back at 0 again.
So let's say it's 10:00AM. I should be getting 36,000 seconds, and if my time is 5:00PM, I should be getting 61,200 seconds.
PS: I do not know the time before hand. The program will figure it out by itself using a currentTime() function.
With Java 8, you could create a Duration instance.
For example :
LocalDateTime date = LocalDateTime.now();
long seconds = Duration.between(date.withSecond(0).withMinute(0).withHour(0), date).getSeconds();
Or more simply you could convert the LocalDateTime to a LocalTime instance and then apply the toSecondOfDay() method :
LocalDateTime date = LocalDateTime.now();
int seconds = date.toLocalTime().toSecondOfDay();
From the java.time.LocalTime javadoc :
public int toSecondOfDay()
Extracts the time as seconds of day, from 0 to 24 * 60 * 60 - 1.
Use a java.time.LocalTime and a java.time.temporal.ChronoField:
// 10:00 AM
LocalTime d = LocalTime.of(10, 0);
System.out.println(d.get(ChronoField.SECOND_OF_DAY)); // 36000
// 05:00 PM
d = LocalTime.of(17, 0);
System.out.println(d.get(ChronoField.SECOND_OF_DAY)); // 61200
// 23:59:59
d = LocalTime.of(23, 59, 59);
System.out.println(d.get(ChronoField.SECOND_OF_DAY)); // 86399
// midnight
d = LocalTime.of(0, 0);
System.out.println(d.get(ChronoField.SECOND_OF_DAY)); // 0
This prints:
36000
61200
86399
0
Notes:
That's just examples. If you want to get the value from the current time, just use LocalTime.now() (or LocalTime.now(ZoneId.of("timezone-name")) as pointed by #Ole V.V.'s answer).
As a timezone-name, always use IANA timezones names (always in the format Continent/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard. You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().
You can also call d.toSecondOfDay() if you want (it's equivalent, as get(ChronoField) internally calls toSecondOfDay).
I suggest:
int secondsOfDay = LocalTime.now(ZoneId.of("Europe/Rome")).toSecondOfDay();
Points to note:
Use an explicit time zone to remind the reader and yourself that the choice of time zone matters and that you have made a conscious choice. Either ZoneId.systemDefault(), or even better is if it would make sense in your situation to give a named zone like for example ZoneId.of("Europe/Rome").
The snippet converts 10:00 AM to 36,000 no matter when the day began; because of summer time and other anomalies it may not have begun at 0:00 midnight, and there may be a gap or overlap early in the morning. To get the true number of seconds since the day began, you will need some calculation involving LocalDate.now(yourTimeZone).atStartOfDay(yourTimeZone).
You can just convert the seconds minutes hour fields into seconds and add them up
Calendar c = new GregorianCalendar();
int totalSecs = c.get(Calendar.SECOND) + 60 * c.get(Calendar.MINUTE) + 3600 * c.get(Calendar.HOUR_OF_DAY);
You could use the SimpleDateFormat to extract the hours minutes and seconds. It works on Java 7 and Java 6 and Java 8, and it adapts to your local time and timezone:
String timeNowHMS[] = new SimpleDateFormat("HH:mm:ss", Locale.ENGLISH)
.format(System.currentTimeMillis())
.split(":");
int secondsPassedInTheDay =
Integer.parseInt(timeNowHMS[0]) * 60 * 60
+ Integer.parseInt(timeNowHMS[1]) * 60
+ Integer.parseInt(timeNowHMS[2]);

Best way to convert months into Milliseconds

I'm trying to convert a no of months into milliseconds
For example:
6 months = X milliseconds
There's no fixed answer to that, because it depends on which months those are - and indeed which year it is. Also potentially which time zone you're in, if you want to take account of that. (I'm assuming you mean the Gregorian calendar, by the way - different calendar systems have different month lengths.)
You could get some sort of "reasonable approximation" by assuming 365.25 days in a year, and saying that 6 months is half of that, then find out that many days in milliseconds. But it would only be an approximation.
For "how many milliseconds does it take to get from date/time X to 6 months later" you'd use an API (even Calendar would work for this particular case, although I'd recommend Joda Time or java.time in Java 8):
Set your start date/time, in the appropriate calendar and time zone
Fetch the "milliseconds since the Unix epoch" (which is easy enough to retrieve in any API) and remember it
Add 6 months
Fetch the "milliseconds since the Unix epoch" again, and subtract the earlier value from it
If you know exactly from when to when those 6 months reach, you can use a variety of ways to calculate the duration, using java.util.Calendar, JodaTime, or the JDK1.8 time API.
But if you don't have particular dates in mind, you can take an average duration for your month.
No API in the world can change that fact.
For example, the JDK1.8 time API uses this for the duration of a month in seconds: (from java.time.temporal.ChronoUnit)
MONTHS("Months", Duration.ofSeconds(31556952L / 12)),
31,556,952 is the number of a seconds in a year, based on a year that lasts 365.2425 days.
You can use the same number directly and get the same result as with the time API:
long months = 6;
long seconds = months * 31556952L / 12;
long milliseconds = seconds * 1000;
Result:
15,778,476,000
Calendar today = Calendar.getInstance();
Calendar sixMonthsAhead = Calendar.getInstance();
sixMonthsAhead.add(Calendar.MONTH, 6);
long differenceInMilis = sixMonthsAhead.getTimeInMillis() - today.getTimeInMillis();
You could also use...
sixMonthsAhead.add(Calendar.DATE, 180);
// or 183 days because 365 / 2 is approximately 183.
instead of...
sixMonthsAhead.add(Calendar.MONTH, 6);
for a more accurate result. But like Jon has mentioned, it will always vary depending on what day of the year it is.
The answer by Jon Skeet is correct.
Joda-Time
Assuming you could specify a pair of beginning and ending points on a time line, here is some example code using the Joda-Time 2.3 library.
This code grabs the current moment, adjusts to first of the month, and adjusts to first moment of that day. Then it adds 6 months. Joda-Time is smart about adding the months, taking into account leap year and various lengths of months. This span of 6 months is then represented as an Interval instance. From that we calculate the number of milliseconds. Note that count of milliseconds needs to be a long (64-bit) rather than an int (32-bit) we Java programmers more commonly use. Lastly, for fun, we see what this span of time looks like when formatted in the ISO 8601 standard’s "Duration" format.
DateTimeZone dateTimeZone = DateTimeZone.forID( "Europe/Paris" ); // Better to specify a time zone than rely on JVM’s default.
DateTime start = new DateTime( dateTimeZone ).withDayOfMonth( 1 ).withTimeAtStartOfDay();
DateTime stop = start.plusMonths( 6 );
Interval interval = new Interval( start, stop );
long milliseconds = interval.toDurationMillis(); // A long, not an int.
Period period = interval.toPeriod(); // For fun… ISO 8601 standard's Duration format.
Dump to console…
System.out.println("start: " + start );
System.out.println("stop: " + stop );
System.out.println("interval: " + interval );
System.out.println("milliseconds: " + milliseconds );
System.out.println("period: " + period );
When run…
start: 2014-04-01T00:00:00.000+02:00
stop: 2014-10-01T00:00:00.000+02:00
interval: 2014-04-01T00:00:00.000+02:00/2014-10-01T00:00:00.000+02:00
milliseconds: 15811200000
period: P6M

Categories