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

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

Related

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

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

subtracting two days from current date in epoch milliseconds java [duplicate]

This question already has answers here:
Java - Subtract Days from date [duplicate]
(6 answers)
Closed 8 years ago.
I am trying to do something really simple. I am trying to subtract 2 days from the current day. I get the number of hours from the UI. So in this example, I get 48 hours from the UI. I am doing the following and I don't know what i'm doing wrong here. I think the result of this is it only subtracts a few minutes from the time.
long timeInEpoch = (currentMillis()/1000 - (48 * 60 * 60)); //48 comes from UI
public long currentMillis(){
return new Date().getTime();
}
d = new Date(timeInEpoch * 1000);
I also tried
d1 = new Date(timeInEpoch);
Nothing seems to work. What am I doing wrong here?
try
long millis = System.currentTimeMillis() - 2 * 24 * 60 * 60 * 1000;
Date date = new Date(millis);
it definitely works
Use Calendar API like this to subtract 2 days from a Date object:
Calendar c = Calendar.getInstance();
c.setTime(d);
c.add(Calendar.DATE, -2);
d.setTime( c.getTime().getTime() );
long millisec = d.getTime();
Your code is alright , your variable d should be at offset of 48 hours from the current time on your server.
Make sure the server and your clients are running on the same time otherwise request your server admins to fix the time on your deployment machine.
You would also notice this difference if your client is opening a browser in e.g. Japan and your server is running in USA because of the standard time difference.
try this
long diff = Math.abs(d1.getTime() - d2.getTime());
long diffDays = diff / (2*24 * 60 * 60 * 1000);
Avoid the old java.util.Date and .Calendar classes as they are notoriously troublesome.
Use either Joda-Time or the new Java.time package built into Java 8. Search StackOverflow for hundreds of Questions and Answers on this.
Joda-Time offers methods for adding and subtracting hour, days, and more. The math is done in a smart way, handling Daylight Saving Time nonsense and other issues.
Quick example in Joda-Time 2.7 ( as this is really a duplicate Question, see others for more info ).
DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( zone );
DateTime fortyEightHoursAgo = now.minusHours( 48 );
DateTime twoDaysAgo = now.minusDays( 2 );

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

Categories