Just like the title says, I've been able to isolate from a text file a string containing a duration in the format of "HH:mm:ss." How would I go about converting it to a duration? I need to convert it to a double that expresses this timestamp in terms of 1 hour, so if it's "08:30:00" I need the double to have a value of 8.5. Not sure exactly how to go about converting it, seems that time is a tricky subject in Java. Any help would be greatly appreciated, even if it's just you saying "use this class" so I can look it up and figure it out.
Thanks!
You can split the expression into parts then parse and calculate duration:
String[] a = "08:30:00".split(":");
double d = Integer.parseInt(a[0]) + Integer.parseInt(a[1]) / 60.0;
tl;dr
Duration.between (
LocalTime.MIN ,
LocalTime.parse ( "08:30:00" )
).toString()
PT8H30M
Duration vs Timestamp
If by the string 08:30:00 you mean "eight and a half hours" span of time, then do not use the term "timestamp". The word “duration” is correct and commonly used. And avoid that format of HH:MM:SS because it is so ambiguous, appearing to be a time-of-day. Instead use the standard format discussed below.
If by the string 08:30:00 you mean “half-past eight in the morning”, then use the word 'timestamp' and avoid the term 'duration'.
These are two very different concepts. You must get clear on them, each should be distinct in your mind. Using the ambiguous format of HH:MM:SS makes that distinction all the more difficult (so avoid that format!).
java.time
The modern way is with the java.time classes.
LocalTime
As mentioned in the comment by Sharma, first parse your string as a LocalTime. This class represents a time-of-day without a date and without a time zone. Having no time zone means these objects are based on a generic 24-hour clock without regard for anomalies such as Daylight Saving Time (DST).
We do not really want a LocalTime as your input string represents a span of time rather than a time-of-day. But this is just the first step.
LocalTime lt = LocalTime.parse ( "08:30:00" );
Duration
To represent the desired span-of-time, we want the Duration class. This class is for spans of time not attached to the timeline. We can create one by converting that LocalTime via getting the amount of time from the beginning of the time-of-day clock, 00:00:00.0 or LocalTime.MIN, and the lt we just instantiated.
Duration d = Duration.between ( LocalTime.MIN , lt );
ISO 8601
We can see the result by generating a String in standard ISO 8601 format for durations by simply calling Duration::toString. The java.time classes use ISO 8601 by default when parsing/generating strings. For durations, the standard format is PnYnMnDTnHnMnS where the P marks the beginning and the T separates the years-months-days portion from the hours-minutes-seconds portion. So, our eight-and-a-half hours will appear as PT8H30M.
System.out.println ( "d.toString(): " + d );
d.toString(): PT8H30M
Avoid decimal numbers for date-time values
For handling such duration values, I strongly suggest using the Duration object in your Java code and the ISO 8601 format when serializing to text.
Using objects in your code provides type-safety, makes your code more self-documenting, and ensures valid values.
Using ISO 8601 format for text makes for values that can easily be parsed, is a format easily read by humans, and is unambiguous in its meaning unlike 08:30:00 which can be misread as a time-of-day.
Your desired format of a decimal number like 8.5 is ambiguous (easy to lose track of its meaning). Also a decimal number is awkward and often incorrect when using a floating-point type (float, Float, double, Double) as these types generate extraneous incorrect digits at the far end of the decimal fraction. Floating-point technology purposely trades away accuracy to gain speed of execution.
BigDecimal
If you must use a fractional number, and want accuracy, use the BigDecimal class.
In this example, I assume you want hours and minutes while truncating any fractional minute. So I call toMinutes on the Duration.
BigDecimal minutesPerHour = new BigDecimal ( 60L ); // Use var/constant for clarity of your intent.
BigDecimal minutes = new BigDecimal ( d.toMinutes () );
BigDecimal fractionalHours = minutes.divide ( minutesPerHour );
frationalHours.toString(): 8.5
See this example code live in IdeOne.com.
You might want to use BigDecimal facility for rounding if you insist on using these decimals rather than Duration objects and ISO 8601 text.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
I would use String.split() to accomplish this. That will split it into an array based on the regex/separators that you specify in the parameters. Something like this,
String time = "08:30:00";
String[] splitValues = time.split(":");
double hour = splitValue[0];
double minute = splitValue[1];
double seconds = splitValue[2];
You could then add up the values. You know that there are 60 minutes in an hour, and 60 seconds in a minute. You could convert these to hours by dividing by 60 and 3600, respectively. Then, it's just a simple matter of addition.
Related
I have received a string in format "yyyy-MM-dd'T'HH:mm:ssXXX"
e.g. "2020-06-01T11:04:02+02:00"
I want to convert it into "yyyy-MM-dd'T'HH:mm:ss:SSSZ"
e.g "2020-06-01T11:04:02.000+0200"
I don't know the time zone actually. It should take from that last part of string as it is.
I have tried but it is taking my local time and time zone when I convert string to date(i.e IST).
SimpleDateFormat sd1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
//sd1.setTimeZone(TimeZone.getTimeZone("PST"));
Date dt = sd1.parse("2020-06-01T11:04:02+02:00");
SimpleDateFormat sd2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss:SSSZ");
System.out.println(sd2.format(dt));
Output:
2020-06-01T14:34:02:000+0530
Only date is right, time and timezone has changed.
I know I am doing it wrong, it will be really helpful if someone can tell me how can I do this.
Thanks for the help.
OffsetDateTime
You said:
I have received a string in format "yyyy-MM-dd'T'HH:mm:ssXXX"
e.g. "2020-06-01T11:04:02+02:00"
No need to define a formatting pattern. Your input complies with the ISO 8601 standard.
These standard formats are used by default in the java.time classes when parsing/generating strings.
Your input should be parsed as a OffsetDateTime.
String input = "2020-06-01T11:04:02+02:00" ;
OffsetDateTime odt = OffsetDateTime.parse( input ) ;
odt.toString(): 2020-06-01T11:04:02+02:00
Offset-from-UTC versus time zone
You said:
I don't know the time zone actually.
That +02:00 on the end is not a time zone. That text represents a mere offset-from-UTC. An offset is just a number of hours-minutes-seconds, positive or negative. A time zone is much more. A time zone is a history of the past, present, and future changes to the offset used by the people of a particular region. A time zone has a name in the format of Continent/Region, such as Europe/Brussels or Africa/Cairo.
You can adjust from a mere offset to a specific time zone. Apply a ZoneId to get a ZonedDateTime.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
zdt.toString(): 2020-06-01T14:34:02+05:30[Asia/Kolkata]
You said:
It should take from that last part of string as it is.
I am not sure what you meant by that. If you parse your input as an OffsetDateTime, that object knows its offset, accessible as a ZoneOffset.
ZoneOffset offset = odt.getOffset() ;
See the code shown in this Answer run live at IdeOne.com.
offset.toString(): +02:00
Formatting strings
You said:
I want to convert it into "yyyy-MM-dd'T'HH:mm:ss:SSSZ"
e.g "2020-06-01T11:04:02.000+0200"
Not sure what you mean here. Do you mean to force the display of milliseconds even if the value is zero? Firstly, you should know that java.time objects have a resolution of nanoseconds for up to nine decimal digits, much finer that the milliseconds shown in 3 digits of a decimal fraction. Secondly, forcing display of fractional second has been covered on Stack Overflow, such as here. Always search Stack Overflow before posting.
Or do you mean displaying the offset without a COLON character as a delimiter between minutes and seconds?
I advise against this. While dropping the COLON is technically allowed by the ISO 8601 standard, I have seen more than one software library or system fail to handle an offset without that delimiter. Ditto for using an offset of hours without the minutes. I advise always using the hours, the minutes, and the delimiter.
If you insist, use DateTimeFormatter with a formatting pattern. Study the Javadoc, keeping mind that the formatting codes are (a) case-sensitive, and (b) sensitive to repeating the character 0, 1, or more times. Here we use xx to get the hours and minutes of an offset without the COLON character delimiting. (Again, I do not recommend that format.)
Code shown in that same IdeOne.com page.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSxx" ) ;
String output = odt.format( f ) ;
output: 2020-06-01T11:04:02.000+0200
Date::toString injects time zone
You said:
I have tried but it is taking my local time and time zone when I convert string to date(i.e IST).
The java.util.Date::toString method tells a lie. While well-intentioned, that method unfortunately applies the JVM’s current default time zone to the Date value as it generates the text. The Date class actually represents a moment in UTC. This is one of many reasons to never use Date. That class nowadays is replaced by java.time.Instant.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes. Hibernate 5 & JPA 2.2 support java.time.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The first suggestion I would make to you is to switch from using the Date object to LocalDateTime (java 8+)
Using the new API would work in this way
String YOUR_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ssXXX";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YOUR_DATE_TIME_PATTERN);
LocalDateTime dateTime = LocalDateTime.parse(input_date, formatter);
//Then you can set your timezone in this way - remember to replace the values with the proper timezone you want.
ZonedDateTime zonedUTC = dateTime.atZone(ZoneId.of("UTC"));
ZonedDateTime zonedIST = zonedUTC.withZoneSameInstant(ZoneId.of("Asia/Kolkata"));
let me know if that works for you
To elaborate the comment and picking up on #Daniel Vilas-Boas answer, you should go for Java8 and I think what you want is something like:
public static void main(String[] args) {
String YOUR_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ssXXX";
String YOUR_NEW_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss:SSSZ";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YOUR_DATE_TIME_PATTERN);
DateTimeFormatter newFormatter = DateTimeFormatter.ofPattern(YOUR_NEW_DATE_TIME_PATTERN);
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2020-06-01T11:04:02+02:00", formatter);
ZoneId from = ZoneId.from(zonedDateTime);
System.out.println(from);
ZonedDateTime zonedIST = zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Kolkata"));
System.out.println(zonedDateTime.format(newFormatter));
System.out.println(zonedIST.format(newFormatter));
}
The prints should print:
2020-06-01T11:04:02:000+0000
2020-06-01T16:34:02:000+0530
EDIT
Included ZoneId to allow handling different timezones.
I have to create the XMLGregorianCalendar object with this date format "YYYY-MM-DDTHH:MI:SS±TZ" e.g. "2015-07-01T17:42:49+04"
I have no idea how to do this. I've used a number of ways on how to convert date, but this pattern doesn't seem to work.
After some experiments I found that "YYYY-MM-dd'T'HH:mm:ssX" will give me the desired output. But it's a string and I can't achieve the same format with XMLGregorianCalendar.
It gives me "2015-07-01T17:42:4234+05:00", as you see there're additional symbols that i don't need.
Date-time objects have no format
XMLGregorianCalendar object with this date format
Date-time objects such as XMLGregorianCalendar do not have a “format”. They internally represent the date-time value in some manner, though not likely to be in text.
You can instantiate date-time objects by parsing text. And your date-time objects can generate text representing their internal value. But the text and the date-time object are distinct and separate from one another.
java.time
The XMLGregorianCalendar class is now obsolete. Supplanted by the modern java.time classes defined in JSR 310.
Parse your input string as a OffsetDateTime as in includes an offset-from-UTC but not a time zone.
OffsetDateTime odt = OffsetDateTime.parse( "2015-07-01T17:42:49+04" );
Generate text in standard ISO 8601 format.
String output = odt.toString() ; // Generates text in ISO 8601 format.
2015-07-01T17:42:49+04:00
Parts of an offset
The part at the end is the offset-from-UTC, a number of hours-minutes-seconds ahead or behind the prime meridian. In ISO 8601, the Plus sign is a positive number that means ahead of UTC. A Minus sign is a negative number that means behind UTC.
Suppressing parts of an offset
Some people may drop the seconds when zero, or drop the minutes when zero. But suppressing those digits does not change the meaning. These three strings all represent the very same moment:
2015-07-01T17:42:49+04
2015-07-01T17:42:49+04:00
2015-07-01T17:42:49+04:00:00
You said:
"2015-07-01T17:42:4234+05:00", as you see there're additional symbols that i don't need.
[I assume you really meant "2015-07-01T17:42:49+04:00" but made typos.]
You really should not care about this. Indeed, I recommend you always include both the hours and the minutes as I have seen multiple libraries/protocols that expect both hours and minutes, breaking if omitted. While the minutes and seconds are indeed optional in ISO 8601 when their value is zero, I suggest you always include the minutes when zero.
DateTimeFormatter
If you insist otherwise, you will need to use DateTimeFormatter class, and possibly DateTimeFormatterBuilder, to suppress the minutes when zero. Perhaps this:
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ssx" );
String output = odt.format( f );
2015-07-01T17:42:49+04
The x code in that formatting pattern suppressed the minutes, and seconds, if their value is zero.
If doing your own formatting, be sure to not truncate when non-zero, or your result will be a falsehood (a different moment). Take for example, representing this moment as seen in India where current the offset in use is five and half hours (an offset that includes 30 minutes rather than zero).
ZoneId z = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );
OffsetDateTime odtKolkata = zdt.toOffsetDateTime();
Dump to console.
System.out.println( "odtKolkata = " + odtKolkata );
2015-07-01T19:12:49+05:30
XMLGregorianCalendar
If you absolutely must use the old legacy class XMLGregorianCalendar, you can create one from the ISO 8601 output of our OffsetDateTime object seen in code above. See this Answer on another Question.
XMLGregorianCalendar xgc = null;
try
{
xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar( odt.toString() );
}
catch ( DatatypeConfigurationException e )
{
e.printStackTrace();
}
System.out.println( "xgc.toString(): " + xgc );
xgc.toString(): 2015-07-01T17:42:49+04:00
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
I'm a little bit frustrated of java 8 date format/parse functionality. I was trying to find Jackson configuration and DateTimeFormatter to parse "2018-02-13T10:20:12.120+0000" string to any Java 8 date, and didn't find it.
This is java.util.Date example which works fine:
Date date = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZZZ")
.parse("2018-02-13T10:20:12.120+0000");
The same format doesn't work with new date time api
ZonedDateTime dateTime = ZonedDateTime.parse("2018-02-13T10:20:12.120+0000",
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ss.SSSZZZ"));
We should be able to format/parse date in any format suitable for FE UI application. Maybe I misunderstand or mistake something, but I think java.util.Date gives more format flexibility and easier to use.
tl;dr
Until bug is fixed:
OffsetDateTime.parse(
"2018-02-13T10:20:12.120+0000" ,
DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" )
)
When bug is fixed:
OffsetDateTime.parse( "2018-02-13T10:20:12.120+0000" )
Details
You are using the wrong classes.
Avoid the troublesome old legacy classes such as Date, Calendar, and SimpleDateFormat. Now supplanted by the java.time classes.
The ZonedDateTime class you used is good, it is part of java.time. But it is intended for a full time zone. Your input string has merely an offset-from-UTC. A full time zone, in contrast, is a collection of offsets in effect for a region at different points in time, past, present, and future. For example, with Daylight Saving Time (DST) in most of North America, the offsets change twice a year growing smaller in the Spring as we shift clocks forward an hour, and restoring to a longer value in the Autumn when we shift clocks back an hour.
OffsetDateTime
For only an offset rather than a time zone, use the OffsetDateTime class.
Your input string complies with the ISO 8601 standard. The java.time classes use the standard formats by default when parsing/generating strings. So no need to specify a formatting pattern.
OffsetDateTime odt = OffsetDateTime.parse( "2018-02-13T10:20:12.120+0000" );
Well, that should have worked. Unfortunately, there is a bug in Java 8 (at least up through Java 8 Update 121) where that class fails to parse an offset omitting the colon between hours and minutes. So the bug bites on +0000 but not +00:00. So until a fix arrives, you have a choice of two workarounds: (a) a hack, manipulating the input string, or (b) define an explicit formatting pattern.
The hack: Manipulate the input string to insert the colon.
String input = "2018-02-13T10:20:12.120+0000".replace( "+0000" , "+00:00" );
OffsetDateTime odt = OffsetDateTime.parse( input );
DateTimeFormatter
The more robust workaround is to define and pass a formatting pattern in a DateTimeFormatter object.
String input = "2018-02-13T10:20:12.120+0000" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" );
OffsetDateTime odt = OffsetDateTime.parse( input , f );
odt.toString(): 2018-02-13T10:20:12.120Z
By the way, here is a tip: I have found that with many protocols and libraries, your life is easier if your offsets always have the colon, always have both hours and minutes (even if minutes are zero), and always use a padding zero (-05:00 rather than -5).
DateTimeFormatterBuilder
For a more flexible formatter, created via DateTimeFormatterBuilder, see this excellent Answer on a duplicate Question.
Instant
If you want to work with values that are always in UTC (and you should), extract an Instant object.
Instant instant = odt.toInstant();
ZonedDateTime
If you want to view that moment through the lens of some region’s wall-clock time, apply a time zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );
See this code run live at IdeOne.com.
All of this has been covered many times in many Answers for many Questions. Please search Stack Overflow thoroughly before posting. You would have discovered many dozens, if not hundreds, of examples.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Short: Not a bug, just your pattern is wrong.
Please use the type OffsetDateTime which is especially designed for time zone offsets and use a pattern this way:
OffsetDateTime odt =
OffsetDateTime.parse(
"2018-02-13T10:20:12.120+0000" ,
DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSZZZ" )
)
Problems in detail:
a) 12-hour-clock versus 24-hour-clock
"h" indicates the hour of AM/PM on a 12-hour-clock but you obviously need "H" for the 24-hour-clock as required by ISO-8601.
b) The form of zero offset
If you want to parse zero offset like "+0000" instead of "Z" (as described in ISO-paper) you should not use the pattern symbol "X" but "ZZZ". Citing the pattern syntax:
Offset Z: This formats the offset based on the number of pattern
letters. One, two or three letters outputs the hour and minute,
without a colon, such as '+0130'. The output will be '+0000' when the
offset is zero.
c) Your input is NOT ISO-8601-compatible therefore no bug in Java
Your assumption that "2018-02-13T10:20:12.120+0000" shall be valid ISO is wrong because you are mixing basic format (in the offset part) and extended format which is explicitly prohibited in ISO-paper (see sections 4.3.2 (example part) and 4.3.3d). Citing ISO-8601:
[...]the expression shall either be completely in basic format, in which
case the minimum number of separators necessary for the required
expression is used, or completely in extended format[...]
The statement of B. Bourque that java.time has a bug is based on the same wrong expectation about ISO-compatibility. And the documentation of let's say ISO_OFFSET_DATE_TIME describes the support of the extended ISO-format only. See also the related JDK issue. Not all ISO-8601-variants are directly supported hence a pattern-based construction of the parser in the right way is okay.
if offset +0000 try this
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" )
LocalDate from =LocalDate.parse("2018-02-13T10:20:12.120+0000",f);
just a question what i am doing wrong. I have this code:
public static int berechneSekundenwert(String datum, String zeit) throws ParseException {
Date dt = new Date();
SimpleDateFormat df = new SimpleDateFormat( "dd.MM.yyyy HH:mm:ss" );
dt = df.parse( datum+" "+ zeit);
int gesamtzeit = (int)dt.getTime();
return gesamtzeit;
}
Now my import format is:
09.11.2019 01:30:17
What i want to do is calculate the time passed for these dates, so i
can later sort them by time. But i get negative values?!
Example output (passed time, date, daytime):
-2120215336 30.09.2019 12:03:35
1757321960 25.09.2019 16:06:25
-2111322336 30.09.2019 14:31:48
-1281127040 21.08.2019 12:05:36
-1280681040 21.08.2019 12:13:02
377782960 09.09.2019 16:54:06
1301386664 09.11.2019 01:30:17
710621960 13.09.2019 13:21:25
712564960 13.09.2019 13:53:48
Shouldn't they all be positive, since java states, that the getTime function measures the time since 01.01.1970
Anyone knows what i did wrong?
Computers use something called a timestamp to represent dates. In Java, Date::getTime() returns the milliseconds passed since 1970-01-01T00:00:00.000Z up to the date in question as long (64-bit integer).
In the code presented, this value is narrowed down to an int (32-bit integer). By narrowing the long to an int, the highest 32 bits get cut of. The largest value representable by an int is 2^31 - 1. A quick calculation shows that:
(2^31 - 1) (milliseconds)
/ 1000 (milliseconds per second)
/ 60 (seconds per minute)#
/ 60 (minutes per hour)
/ 24 (hours per day)
= 24.8551348032 (days)
This means that after roughly 25 days, the int will overflow (as it is defined in the Two's compliment). Not to mention that a later point in time could have a lower value than an earlier point in time, thus the negative values.
To fix this issue1, I would suggest to define gesamtzeit as long.
Two remarks on your code:
java.util.Date is regarded as outdated. I would suggest to use java.time.Instant instead.
I would suggest to use English in the source code, only exception being you use domain-specific words that cannot (well) be translated to English.
1 This is only a temporary fix. All representation with a fixed number of bits will eventually overflow. In fact, all representation with any memory constraint at all will overflow eventually. I leave it up to the reader to find out when a 64-bit integer will overflow
tl;dr
See correct Answer by Turing85 about 32-bit versus 64-bit integers.
Use only modern java.time classes, never Date/SimpleDateFormat.
Consider the crucial issue of time zone or offset-from-UTC.
Educate the publisher of your data about the importance of (a) including zone/offset info, and (b) using ISO 8601 standard formats.
Code:
LocalDateTime.parse(
"09.11.2019 01:30:17" ,
DateTimeFormatter.ofPattern( "dd.MM.uuuu HH:mm:ss" )
)
.atOffset(
ZoneOffset.UTC
)
.toInstant()
.toEpochMilli()
See this code run live at IdeOne.com.
1573263017000
Details
The correct Answer by Turing85 addresses your specific question as to why the invalid negative numbers. But you have other problems.
ISO 8601
Now my import format is: 09.11.2019 01:30:17
I suggest you educate the publisher of this data about the ISO 8601 standard defining formats to use when communicating date-time values as text.
Legacy date-time classes
You are use terrible date-time classes that were supplanted years ago by the modern java.time classes defined in JSR 310. Never use Date or SimpleDateFormat.
Moment
Apparently you want to get a count of milliseconds since the epoch reference of first moment of 1970 in UTC. But doing that requires a moment, a specific point on the timeline.
Your input does not meet this requirement. Your input is a date and a time-of-day but lacks the context of an offset-from-UTC or a time zone.
So, take your example of 09.11.2019 01:30:17. We cannot know if this is 1:30 in the afternoon of Tokyo Japan, or 1:30 PM in Paris France, or 1:30 in Toledo Ohio US — which are all very different moments, several hours apart on the timeline.
So we must first parse your input as a LocalDateTime. This class represent a date and time without any concept of offset or zone.
String input = "09.11.2019 01:30:17" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd.MM.uuuu HH:mm:ss" ) ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
Perhaps you know for certain the offset or zone intended by the publisher of this data. If so:
Suggest to the publisher of this data that they include the zone/offset info within their data.
Apply a ZoneOffset to get an OffsetDateTime, or a ZoneId to get a ZonedDateTime.
Perhaps you know for certain this input was intended for UTC, that is, an offset of zero hours-minutes-seconds.
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;
To get a count of milliseconds since 1970-01-01T00:00Z convert to the basic building-block class Instant.
Instant instant = odt.toInstant() ;
Interrogate for a count of milliseconds since epoch.
long millisSinceEpoch = instant.toEpochMilli() ;
Understand that your original code ignored the crucial issue of time zone & offset-from-UTC. So your code implicitly applies the JVM's current default time zone. This means your results will vary at runtime, and means you likely have incorrect results too.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
why you downcast the return value ofgetTime()?
just make you method return long instead of int
and replace this line
int gesamtzeit = (int)dt.getTime();
with
long gesamtzeit = dt.getTime();
how to convert timestamp(in microseconds) string to date in Java/Scala.
My goal is to compare two timestamps and find the differences between them.
I'm using java 8 and example Timestamp string is 1474457086337977.
I would like to convert this into Date or Timestamp instance.
tl;dr
Instant.EPOCH.plus(
Duration.ofNanos(
TimeUnit.MICROSECONDS.toNanos(
Long.parse( "1474457086337977" ) ) ) )
java.time
The java.time classes support a resolution of nanoseconds, more than enough for your microseconds.
Parsing a string of a number
Parse the string as a long to get a count of microseconds from the epoch.
long micros = Long.parse( "1474457086337977" );
And of course you can always use an integer literal. Note the L appended to integer literal.
long micros = 1_474_457_086_337_977L ;
Converting a long into Instant
We want to transform that count of microseconds from the epoch of beginning of 1970 in UTC (1970-01-01T00:00:00Z) into an Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds. That means up to nine digits of a decimal fraction.
The Instant class has handy static methods for converting from a count of whole seconds, from a count of whole seconds plus a fractional second in nanoseconds, or from a count of milliseconds. But unfortunately no such methods for a count of microseconds or nanoseconds.
As a workaround, we can define a Duration and add it to the epoch reference date already defined as a constant. We can instantiate a Duration as a number of nanoseconds. To get nanoseconds, we multiply your microseconds by a thousand. Note the use of 64-bit long rather than 32-bit int.
Duration duration = Duration.ofNanos( micros * 1_000L );
Instant instant = Instant.EPOCH.plus( duration );
instant.toString(): 2016-09-21T11:24:46.337977Z
Alternatively, you can use the TimeUnit enum to convert microseconds to nanoseconds without hard-coding a “magic number”.
Duration duration = Duration.ofNanos( TimeUnit.MICROSECONDS.toNanos( micros ) );
To adjust into other offsets or time zones, search StackOverflow for Java classes OffsetDateTime or ZonedDateTime.
Converting to legacy date-time types
You should avoid the old date-time types bundled with the earliest versions of Java. They have proven to be poorly-designed, confusing, and troublesome. Now supplanted by the java.time types.
But if you must interact with old code not yet updated to the java.time types, you may convert to/from java.time. Look to new methods added to the old classes.
java.sql.Timestamp ts = java.sql.Timestamp.from( instant );
Beware of data loss when converting from a java.time type to java.util.Date or java.util.Calendar. These types resolve to only milliseconds. A truncation from nanoseconds to milliseconds is performed silently, lopping off those last six (of nine) possible digits of a fractional second.
java.util.Date utilDate = java.util.Date.from( instant ); // Caution: Data loss in truncating nanoseconds to milliseconds.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time.
Well, what about converting those microseconds to milliseconds and then just create a timestamp object?
long microsecs = 1474457086337977L;
long millis = TimeUnit.MILLISECONDS.convert(microsecs, TimeUnit.MICROSECONDS);
Timestamp time = new Timestamp(millis);
Wouldn't that work?
--Edit
To address the comments left in the answer:
About Java 8's new Date Time API
First, since you mention that you're using Java 8 I totally agree that a better approach would be to use the new Java 8 Date/Time API. However, this is a luxury you don't always have even when working with Java 8 because you may still be interacting with an old API still using the old Java Date/Time classes, or simply because the rest of your API still uses them and you don't want to start mixing things.
It is not clear in your question if you already know this, you seem to be sure that you want to use either java.util.Date or java.sql.Timestamp and I didn't question that, I just worked around the parameters of your question.
Clearly the new Java date/time APIs are much better than the old ones, but there are millions of lines of code out there still using the old APIs and they work. Yet again I thought that was out of the scope of the answer and it seems you already have other good answers here to address that.
About Possible Data Loss
One comment mentions that the answer might run into data loss. I think in Java all integer arithmetic is subject to potential underflow or overflow. My mistake is probably not have mentioned it.
It is true that TimeUnit.convert method might end up causing overflows or underflows in certain scenarios. It is documented in the method.
A nanosecond is one billionth of a second (1/1000000000)
A microsecond is one millionth of a second (1/1000000).
A millisecond is one thousandth of a second (1/1000)
Which means that, once expressed as a long, a millisecond number should be a much smaller number than a microsecond one, right?
The formula used by TimeUnit.convert is as follows
final long MICROS = 1000000L;
final long MILLIS = 1000L;
long microsecs = 1474457086337977L;
long millisecs = microsecs / (MICROS / MILLIS)
Which means you would run into data loss only if your microseconds are really small numbers e.g. if you had less than 1,000 microseconds. You should validate your code never goes into a scenario like this.
One comment left in this answer argues that the right answer should probably use nanoseconds, but then again a nanosecond long value would be a much bigger number than your microseconds and so, during conversions to nanoseconds you might still run into overflows.
For example, think what would happen if you had Long.MAX_VALUE microseconds, how could you convert that to nanoseconds using just Java long arithmetic without an overflow given that nanoseconds are supposed to be a much bigger number than your Long.MAX_VALUE microseconds?
My point being that regardless of you using Java 8 Date Time or legacy Java Date Time APIs you need a long value representing an instant in the time line, but that long has limitations in regards to how far in the past or how far in the future you can go, and when you do conversions between units, that arithmetic is subject to underflow and overflow and there's no way around it and you should be aware of that to avoid very nasty bugs.
Once more, I thought that was a given and outside the scope of the question and I bring it up only because I got some downvotes for this omission.
You can try following code, which will take time stamp as a string:
BigInteger b = new BigInteger("1474457086337977");
b=b.divide(new BigInteger("1000"));
String x =b.toString();
DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
long milliSeconds= Long.parseLong(x);
System.out.println(milliSeconds);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(milliSeconds);
System.out.println(formatter.format(calendar.getTime()));
Or for more accuracy, you can use BigDecimal:
BigDecimal b = new BigDecimal("1474457086337977");
b=b.divide(new BigDecimal("1000"));
String x =b.toString();