Adding a large timestamp to the current time in Java - java

I am working on an application that supports Google 2-step verification. This application also supports a feature to 'trust this device for 30 days'.
I use a database to save all this information such as IP-addresses and expire times. Now when I fill in the timestamp System.currentTimeMillis() + 30 * 24 * 60 * 60 * 1000 to add 30 days to the current time, it inserts a timestamp earlier than the current time into the database.
For example: the current time = 1483223733000 (2016-31-12 11:36 PM UTC+1).
Now when I add 30 days (which is 2592000000 milliseconds, it comes to a date similar to 1481520984841 (2016-12-12 6:36 AM UTC+1) which is not 30 days ahead, but rather about 19 days back in time.

This problem had to do with a 32-bit integer overflow. Since the maximum value for an integer is 2147483647, 30 days in milliseconds would be too large for an integer and would result in an integer like -1702967296 (Which is about -19 days in milliseconds.)
To solve this problem, I use a long instead of an int. So now I do:
System.currentTimeMillis() + 30L * 24 * 60 * 60 * 1000;

You already answered the question of why the calculation is wrong, but I want to recommend you a more idiomatic way to working with dates, if you use Java 8.
If you need to add just 30 24-hour-long days (ie. 24 * 30 hours), use:
Instant.now().plus(Duration.ofDays(30)).toEpochMilli();
or
Instant.now().plus(30, ChronoUnit.DAYS).toEpochMilli();
If you need to add exactly 30 days (some days can be 23 or 25 hours long because of daylight saving time etc) according to the current JVM time zone, use:
ZonedDateTime.now(ZoneId.systemDefault()).plusDays(30).toInstant().toEpochMilli();
or (implicitly use JVM timezone)
ZonedDateTime.now().plusDays(30).toInstant().toEpochMilli();

You could use the Calendar to do this:
Calendar cal = Calendar.getInstance();
System.out.println(cal.getTime());
System.out.println(cal.getTimeInMillis());
//cal.add(Calendar.DATE, 30);
cal.setTimeInMillis(System.currentTimeMillis() + 30L * 24 * 60 * 60 * 1000);
System.out.println(cal.getTime());
System.out.println(cal.getTimeInMillis());

Related

Converting time4j Duration<IsoUnit> from P365D to P1Y and so on

Instant i1 = Instant.now();
Instant i2 = Instant.now().plusSeconds(60 * 60 * 24 * 365);
Duration<IsoUnit> dur = Duration.from((TemporalAmount) java.time.Duration.between(i1, i2));
System.out.println(dur);
this code prints P365D, is there a way to make units fill up the next bigger unit, so this becomes P1Y and if i had like P334D to P11M and so on?
time4j version is 4.38
The other comments and answers are completely right to say that a year is not always equal to 365 days.
The Time4J-method net.time4j.Duration.from(TemporalAmount) returns a normalized duration using STD_PERIOD as normalizer. The documentation of this normalizer says:
Normalizes the duration items on the base of 1 year = 12 months and 1
day = 24 hours and 1 hour = 60 minutes and 1 minute = 60 seconds -
without converting days to months.
So you can only expect the result to be in days when you start with a temporal amount defined in seconds.
If you still want a year then I suggest you to first convert your instants to calendar dates using an appropriate time zone. But in leap years, your code would still produce 365 days and not a year after having added 60 * 60 * 24 * 365 seconds to the second instant. So your addition of seconds is also flawed because it is based on false assumptions.
Side note:
If you want the reverse way, namely how many seconds are in a year then you might use code like
Moment m1 = Moment.nowInSystemTime();
Moment m2 = m1.toZonalTimestamp(ZonalOffset.UTC).plus(1, CalendarUnit.YEARS).atUTC();
long seconds = SI.SECONDS.between(m1, m2); // = 366 days in seconds if applied on date 2019-05-22!
With a future version of Time4J and possible leap second at the end of year 2019, the code might even produce an extra second.
Anyway, I advise you to update Time4J to v5.4 and consider following mappings:
java.time.Instant as input => net.time4j.MachineTime.from(...)
java.time.LocalDateTime/net.time4j.PlainTimestamp => net.time4j.Duration.from(...)
So if you really want years as possible output in printing durations and you have instants/moments then first convert to LocalDateTime/PlainTimestamp (using a time zone or offset) before you create the appropriate duration object.
Update from 2019-05-25:
Another way with the version v5.4 (or later) is possible via "fuzzy" durations. You could normalize the durations you get by applying an approximation. Example:
Duration<IsoUnit> d = Duration.of(60 * 60 * 24 * 365, ClockUnit.SECONDS);
d = d.with(Duration.approximateMaxUnitOnly());
System.out.println(d); // P1Y
Due to the nature of this kind of normalization, you cannot expect exact results.
A year doesn't have a fixed amount of seconds:
Leap years have an additional day on February 29
Leap seconds are sometimes added
Due to above you have to know how many seconds are in a year. It seems like instead of Instant and Duration you should be using LocalDate and Period (at least when using java.time):
LocalDate d1 = LocalDate.now();
LocalDate d2 = d1.plusYears(1);
Period p = Period.between(d1, d2);
System.out.println(p); // P1Y

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]);

Why am I getting the wrong milliseconds for a given string time?

DateFormat df1 = new SimpleDateFormat("kk:mm");
Date d = null;
try {
d = df1.parse("21:00");
} catch (ParseException e) {
e.printStackTrace();
}
I'm getting 61200000 milliseconds but when I convert it online, I get a different value.
SimpleDateFormat is not so simple as the name suggests. In particular its handling of time zone is sometimes obscure. In this case I dare say it uses your JVM’s time zone setting (probably taken over from your computer’s setting), apparently one that is offset 4 hours from UTC. So when the time is 21:00 (9 pm) in your time zone, it’s 17:00 in UTC. The milliseconds value in a Date object is always in UTC, therefore you get 17 * 60 * 60 * 1000 = 61 200 000. If you try it online on a server in a different time zone, you’re likely to get a different result.
java.time.Duration
I think what you really want is Duration.parse("PT21H0M"). This will give you a duration of 21 hours 0 minutes. You can use its toMillis method to get 21 * 60 * 60 * 1000 = 75 600 000.
The Java 8 date and time classes (of which Duration is just one) are generally much more pleasant to work with than the old classes.
Or you can pass a number of hours.
Duration d = Duration.ofHours( 21 );
ISO 8601 duration
The syntax PT21H0M may look a bit odd at first, but its an international standard, ISO 8601, so we’d probably better learn to work with it, and it’s straightforward to learn.
If you do this:
d = df1.parse("21:00");
you get this date
Thu Jan 01 21:00:00 CET 1970
and the epoch is 72000000, to convert that, you need to divide by 1000
verifiable here

Android Calender.getTimeInMillis() units?

I am using Android's Calendar object and I am using the getTimeInMillis() method, but when I look at the Value it gives me it is a really long number. I am trying to replicate this format but I don't know how as when I take the current time in 24 hour mode and convert it to milliseconds I am completely off.
Example:
Calendar.getTimeInMillis() : at 11:46 pm = 1,349,585,220,205
Time at 11:46 pm using formula[(23 * 60 * 60 * 1000) + (46 * 60 * 1000)] = 85,560,000
I'm wondering if there is some kind of formula the calendar is using to convert the current time to Milliseconds and how I can replicate this.
Thank you!
It's the number of milliseconds since the epoch, 1/1/1970. See this article on Unix time.
1,349,585,220,205 milliseconds / (1000 * 3600) = number of hours = 374884.7833902778
374884.7833902778 hours / 24 = 15620.19930792824 days
15620.19930792824 days / 365 days = 42.79506659706368 years
1970 + 42 years = 2012
(This is not precise due to not taking into account daylight savings time. Use a real datetime library!)

How to compare Timestamp to current time less a certain amount of minutes in android

i have a sql.Timestamp object and i need to compare it to the current time minus 45 minutes, how would i go about doing this on Android?
i know i should use the compareTo Method as Timestamp extends java.util.Date , what i dont know how to do is create the date object 45 mins less than current time.
This might be an overkill, but you could create two Calendar instances, one with your timestamp and one with current time, then subtract 45 minutes from the latter and compare them.
Calendar then = Calendar.getInstance();
then.setTime(timestamp);
Calendar now = Calendar.getInstance();
now.add(Calendar.MINUTE, -45);
int diff = now.compareTo(then);
// ...
Timestamp (and Date) objects can be constructed by passing a value of type long as a constructor, with said value representing the number of milliseconds since January 1, 1970.
A millisecond is 1/1000th of a second, so 45 minutes would be 45 * 60 * 1000 milliseconds. Simply create two Timestamp instances - one using the long value that represents the time you want to compare (if you don't already have a Timestamp instance) and one using the long value that represents the time 45 minutes ago (System.currentTimeMillis() - (45 * 60 * 1000)), then compare those.

Categories