I´m using a third-part service that returns to me dates in this format:
"EndDate":"\/Date(1487615921387-0300)\/","StartDate":"\/Date(1487608721387-0300)\/"
My problem is to convert this date to LocalDate or LocalDateTime. I found some answers here, but they were using joda time, so not helpful.
You need to learn the meaning of your input data.
The last part -0300 is likely an offset-from-UTC, a number of hours ahead of or behind UTC. I suggest use the format with a colon (-03:00) but without is acceptable. You need to know if the plus/minus sign means ahead of or behind UTC. Modern protocols tend to use a plus for ahead of UTC and a minus for behind, but there are protocols that do the opposite.
Know that an offset is not a time zone. A time zone is a history of offsets for a particular region with rules for anomalies such as Daylight Saving Time (DST).
The first part is likely a count of milliseconds since an epoch reference date. We can guess that your epoch is the commonly used first moment of 1970 in UTC (1970-01-01T00:00:00). But there are at least a couple dozen epochs used by various known software systems. Again, you must consult the source of your data.
This particular combination of a count-from-epoch with offset I've seen before. It confounds me as it makes more sense to simply use a count-from-epoch in UTC without an offset. If you want to show a date-time adjusted into a time zone, use the standard ISO 8601 string formats.
I will guess that your input number is a count from epoch in milliseconds in UTC. So we parse it as a Instant object. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
String input = "1487615921387-0300";
String inputCount = input.substring ( 0 , 13 ); // zero-based index counting.
long count = Long.parseLong ( inputCount );
Instant instant = Instant.ofEpochMilli ( count );
We can parse the offset as a ZoneOffset object.
String inputOffset = input.substring ( 13 );
ZoneOffset offset = ZoneOffset.of ( inputOffset );
Apply that ZoneId to see the same moment as a wall-clock time in another offset as an OffsetDateTime.
OffsetDateTime odt = instant.atOffset ( offset );
See this code run live at IdeOne.com.
input: 1487615921387-0300
inputMillis: 1487615921387
inputOffset: -0300
count: 1487615921387
instant.toString(): 2017-02-20T18:38:41.387Z
odt.toString(): 2017-02-20T15:38:41.387-03:00
Note the three hour difference between instant and odt, hours 18 versus 15, the effect of the offset. Still the same simultaneous moment, same point on the timeline, but seen with a different wall-clock time.
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.
Ok first you should to extract your Dates from your String i use a patttern the idea is simple
public static void main(String[] args) {
String str = "\"EndDate\":\"\\/Date(1487615921387-0300)\\/\",\"StartDate\":\"\\/Date(1487608721387-0300)\\/\"";
//Get Long from your String between Date( and )
String start = "Date(", end = ")";
String regexString = Pattern.quote(start) + "(.*?)" + Pattern.quote(end);
Pattern pattern = Pattern.compile(regexString);
Matcher matcher = pattern.matcher(str);
List<String> res = new ArrayList<>();
while (matcher.find()) {
//now we get results like this 1487608721387-0300
res.add(matcher.group(1));
}
//You can change the format like you want
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date;
String[] split;
for (String s : res) {
split = s.split("-");
///we should to split the String to get the first part 1487608721387
//then we get Date from this String
date = new Date(new Long(split[0]));
//Set time zone to your format i'm not sure if it is correct you can avoid it
//format.setTimeZone(TimeZone.getTimeZone(split[1]));
//Show your date
System.out.println(format.format(date));
}
}
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.
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();
I have a timestamp encoded as a String—for example, "2012-02-12T09:08:13.123456-0400", coming from an Oracle database.
The only way that I can think of reading this timestamp, is by using Timestamp.valueOf(), and that requires a format of yyyy-[m]m-[d]d hh:mm:ss[.f...]
I am convinced that this is the only way to read time without losing precision because other ways do not support nanosecond precision included in the example above (".123456").
With that in mind, I can simply trim the needed values, to fit the required format. Hence, the original string would be transformed:
Before: "2012-02-12T09:08:13.123456-0400"
After: "2012-02-12 09:08:13.123456"
If I do this, I remove the "-0400" timezone offset. This comes as a red flag to me, until I saw this post. One of the proposed answers states,
I think the correct answer should be java.sql.Timestamp is NOT timezone specific. Timestamp is a composite of java.util.Date and a separate nanoseconds value. There is no timezone information in this class. Thus just as Date this class simply holds the number of milliseconds since January 1, 1970, 00:00:00 GMT + nanos.
To prove to myself that the offset is not needed, I wrote a simple integration test.
Insert this timestamp into the database: "2015-09-08 11:11:12.123457". Read the database using Java, and print out the details. I get "2015-09-08 11:11:12.123457", which is the same value. This happens to be ok, since my JVM and the Oracle DB are running on the same machine.
Is it a fact that a timezone is not factor in java.sql.Timestamp?
Is there a better way to read that entire timestamp, without losing any precision in Java 7?
tl;dr
org.threeten.bp.OffsetDateTime odt =
OffsetDateTime.parse(
"2012-02-12T09:08:13.123456-0400",
org.threeten.bp.format.DateTimeFormatter.ofPattern( "yyyy-MM-dd'T'HH:mm:ssZ" ) // Specify pattern as workaround for Java 8 bug in failing to parse if optional colon is not present.
)
;
Using java.time
Rather than receiving a String from your database, you should retrieve an object, a date-time object, specifically a java.time object.
The java.time classes supplant the troublesome old date-time classes including java.sql.Timestamp. If your JDBC driver supports JDBC 4.2 and later, you can pass and receive java.time objects directly.
Instant
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction). So this is equivalent to java.sql.Timestamp including support for the six digits of microseconds of your input data, so no precision lost per the requirements of your Question.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
instant.toString(): 2012-02-12T13:08:13.123456Z
ZonedDateTime
If you want to see that same moment through the lens of a particular region's wall-clock time, apply a ZoneId to get a ZonedDateTime object.
ZoneId z = ZoneId.of( "America/St_Thomas" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString(): 2012-02-12T09:08:13.123456-04:00[America/St_Thomas]
OffsetDateTime
As for your direct Question of how to make sense of the string 2012-02-12T09:08:13.123456-0400 as a date-time value, parse as an OffsetDateTime.
A time zone has a name in the format of continent/region, and represents a history of past, present, and future changes to a region’s offset caused by anomalies such as Daylight Saving Time (DST). We have clue as to the time zone with your string, so we use OffsetDateTime rather than ZonedDateTime.
OffsetDateTime odt = OffsetDateTime.parse( "2012-02-12T09:08:13.123456-0400" ) ;
Well, that line of code above should have worked, but in Java 8 there is a small bug in parsing the offset lacking the optional COLON character between the hours and minutes. So -04:00 in Java 8 will parse but not -0400. Bug fixed in Java 9. Your String is indeed compliant with the ISO 8601 standard for date-time formats used by default in the java.time classes. Tip: Generally best to always format your offsets with the colon, and both hours/minutes and with a padding zero – I've seen other protocols and libraries expect only such full format.
Until you move to Java 9, specify the formatting pattern explicitly rather than rely on the implicit default pattern, as a workaround for this bug.
OffsetDateTime odt =
OffsetDateTime.parse(
"2012-02-12T09:08:13.123456-0400",
DateTimeFormatter.ofPattern( "yyyy-MM-dd'T'HH:mm:ssZ" ) // Specify pattern as workaround for Java 8 bug in failing to parse if optional colon is not present.
)
;
Converting
If your JDBC driver is not yet compliant with JDBC 4.2, retrieve a java.sql.Timestamp object, for use only briefly. Immediately convert to java.time using new methods added to the old date-time classes.
java.sql.Timestamp ts = myResultSet.getTimestamp( … ) ;
Instant instant = ts.toInstant();
Proceed to do your business logic in java.time classes. To send a date-time back to the database convert from Instant to java.sql.Timestamp.
myPreparedStatement.setTimestamp( … , java.sql.Timestamp.from( instant ) ) ;
Java 6 & 7
In Java 6 & 7, the above concepts still apply, but java.time is not built-in. Use the ThreeTen-Backport library instead. To obtain, see bullets below.
In Java 7, you cannot use JDBC 4.2 features. So we cannot directly access java.time objects from the database through the JDBC driver. As seen above, we must convert briefly into java.sql.Timestamp from Instant. Call the utility methods DateTimeUtils.toInstant(Timestamp sqlTimestamp) & DateTimeUtils.toSqlTimestamp(Instant instant).
java.sql.Timestamp ts = myResultSet.getTimestamp( … ) ;
Instant instant = DateTimeUtils.toInstant( ts ) ;
…and…
java.sql.Timestamp ts = DateTimeUtils.toSqlTimestamp( instant ) ;
myPreparedStatement.setTimestamp( … , ts ) ;
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, Java 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 Java 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.
java.sql.Timestamp.valueOf(String) parses the provided time in the current timezone. You can check this by looking at the implementation, which in the end simply calls Timestamp(int year, int month, int date, int hour, int minute, int second, int nano) which calls public Date(int year, int month, int date, int hrs, int min, int sec), which says (emphasis mine):
Allocates a Date object and initializes it so that it represents the instant at the start of the second specified by the year, month, date, hrs, min, and sec arguments, in the local time zone.
It is true that Timestamp doesn't have time zone information (it is just a wrapper with number of seconds since the GMT epoch + nanoseconds), but when loading or storing a Timestamp, JDBC will use the local (default) timezone, unless explicitly declared otherwise.
This means that a Timestamp at 10:00 in your local timezone will end up in the database as an SQL TIMESTAMP at 10:00, and not at - for example - 08:00 if your timezone is 2 hours ahead of GMT; and the reverse when loading.
You are correct that java.sql.Timestamp has no timezone information. Under the covers it is just an instant that is milliseconds since the epoch and the epoch itself is defined with essentially a 0 offset, January 1, 1970, 00:00:00 GMT.
That being said, when working with times, offset always matters and this will lead you into the hell, er, "dynamic world" that is ISO-8601 in Java 8 java.time. The offset matters a lot, unless you are standing in Greenwich, England. If you try to just ignore it you may sometimes guess the day wrong; it is Monday in Greenwich 8 hours earlier than it is Monday in Seattle, for example. I don't think Java8 has a built in DateTimeFormatter for the -0000 variants of ISO-8601, but if you are sure your format is "stable", this would work.
public void java8TimeWTF() {
OffsetDateTime odt = OffsetDateTime.parse(
"2012-02-12T09:08:13.123456-0400",
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.nZ"));
Instant i = odt.toInstant();
System.out.printf("odt: %s, i: %s\n", odt, i);
}
Outputs odt: 2012-02-12T09:08:13.000123456-04:00, i: 2012-02-12T13:08:13.000123456Z
Here's what we had to do to deal with all the variant's of ISO-8601 coming out of our clients
import org.testng.annotations.Test;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import static org.testng.Assert.assertEquals;
public class Java8Time8601 {
private final long EXPECTED_MILLIS = 1493397412000L;
public Instant iso8601ToInstant(String s) {
DateTimeFormatter[] dateTimeFormatters = {
DateTimeFormatter.ISO_INSTANT,
DateTimeFormatter.ISO_OFFSET_DATE_TIME,
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ")
};
for (DateTimeFormatter dtf : dateTimeFormatters) {
try {
OffsetDateTime odt = OffsetDateTime.parse(s, dtf);
Instant i = odt.toInstant();
return i;
} catch (DateTimeParseException dtpe) {
;
}
}
throw new IllegalArgumentException(String.format("failed to parse %s", s));
}
#Test
public void testInstantParse8601_Z() throws Exception {
String[] candidates = {
"2017-04-28T16:36:52.000Z",
"2017-04-28T16:36:52.00Z",
"2017-04-28T16:36:52.0Z",
"2017-04-28T16:36:52Z",
"2017-04-28T16:36:52+00:00",
"2017-04-28T16:36:52-00:00",
"2017-04-28T09:36:52-07:00",
"2017-04-28T09:36:52-0700",
};
for (String candidate : candidates) {
Instant i = iso8601ToInstant(candidate);
assertEquals(i.toEpochMilli(), EXPECTED_MILLIS, String.format("failed candidate %s", candidate));
System.out.println(i.toString());
}
}
}
There has got to be a better way.
I want to achieve a similar operation in java:
time = "2014-05-19 13:36:05"
interval = "60 (seconds)"
time - interval = "2014-05-19 13:35:05"
What's the best approach to express this in Java given the following constraints:
The datetime is a formated string.
The interval is an integer.
The calculated time should be also a datetime formatted string.
You should work with "Date" objects, which basically represent an instance in time (number of milliseconds since Unix epoch) when doing the subtraction. Once you have a "Date" Object you can use "getTime" method (http://docs.oracle.com/javase/7/docs/api/java/util/Date.html#getTime()) to get this milliseconds value, and subtract 60 seconds (make sure to work with milliseconds not seconds!), and create a new "Date" with that resulting value.
This is one approach. There are many, Joda library is also quite popular. It has a method to subtract milliseconds from its date representation, http://www.joda.org/joda-time/apidocs/org/joda/time/DateTime.html#minusSeconds(int).
Try using the joda-time library.
Here is the class to parse the date string.
Use:
dateTime.minusSeconds(int sec);
method to substract your interval.
java.time
The modern way is with java.time classes.
Do not conflate a point-in-time (a moment) with a span-of-time (a duration). Avoid representing a span-of-time using time-of-day notation as that creates ambiguity and confusion. Use standard ISO 8601 formatted strings to represent a duration: PnYnMnDTnHnMnS.
Do not conflate a date-time value (object) with a String representation. A date-time object can parse or generate a String but is distinct and separate from the String.
The java.time framework is rich with various date-time classes. Use these to represent your data as objects rather than mere numbers and strings.
The java.time classes use standard ISO 8601 formatted strings by default.
String input = "2014-05-19T13:36:05" ;
LocalDateTime ldt = LocalDateTime.parse( input );
Duration d = Duration.ofSeconds( 60 );
LocalDateTime later = ldt.plus( d );
ld.toString(): 2014-05-19T13:36:05
d.toString(): PT1M
later.toString(): 2014-05-19T13:37:05
See live code in IdeOne.com.
Note that LocalDateTime lacks any concept of time zone or offset-from-UTC. So this does not represent a moment on the timeline. Apply a zone or offset if you know one was intended. Already covered many times on Stack Overflow; search for OffsetDateTime and ZonedDateTime.
As for database and SQLite, there are many other Questions and Answers already handling this. Your JDBC 4.2 driver may handle conversion of java.time types directly. If not, store as string using standard ISO 8601 format.
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….
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.
You should work only with Date object instread of String. Format your date into string only when you whant to display it.
With a Date object you will be able to get the value in ms and do computation on it. You can also use Calendar to breakdown a date.
You should not work with String objects but Date instead. Only format date if and when you want to display it.
Date originalDate = new Date();
long diff = 60 * 1000; // milliseconds!
Date diffedDate = new Date(originalDate.getTime() - diff);
If you really want to do it the string way (which you should not), you can parse the date string like this:
String originalDateString = getDateTime(); // your current function
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date badlyDesignedOriginalDate = dateFormat.parse(originalDateString);
long diff = 60 * 1000; // milliseconds!
Date diffedDate = new Date(badlyDesignedOriginalDate.getTime() - diff);
But again, you should not do this.
You could use something like this:
long minute = 1000*60;
Date date1 = new Date(); //current date
Date date2 = new Date(date1.getTime() - minute); //new date, 1 minute older
//or another method
long minute = 1000*60;
Date date1 = new Date();
date1.setTime(date1.getTime() - minute);
Date works with milliseconds since January 1, 1970, 00:00:00 GMT, so you can substract it like normal numbers.
I got the following date format that I get from an API (Yes I tried to get them to change the API... dailywtf story):
\/Date(1310481956000+0200)\/
How can I convert this into a Java Date? (java.util.Date)
This comes from a .NET JSON web service.
Without knowing what the date/time string stands for, let me make a guess.
The 1310481956000 looks to be milliseconds after epoch, and the +0200 an offset relative to GMT.
The following code seem to indicate it as well:
final TimeZone tz = TimeZone.getTimeZone("GMT+0200");
final Calendar cal = Calendar.getInstance(tz);
cal.setTimeInMillis(1310481956000L);
final SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
f.setTimeZone(tz);
System.out.println(f.format(cal.getTime()));
Prints 2011-07-12 16:45:56 GMT+02:00
How can I convert this into a Java Date? (java.util.Date)
First, get "them" to clearly and precisely tell you exactly what that date format means. (If they won't or can't you could guess; see below.)
Next write a custom parser to parse the String and extract the information content.
Finally, convert the information content into a form that matches one of the Date constructors and create an instance.
My guess is that the 1310481956000 part is the number of milliseconds since the UNIX epoch (1970/01/01T00:00) and that the 0200 represents a timezone offset of 2 hours (MET?). However, you shouldn't rely on a guess. Get "them" to give you the specification, or at least a number of examples and the actual times/timezones that they correspond to.
You'll have to get the format from the API provider but it seems like a epoch + an offset for time zones. To convert it you could try.
final String fromAPI = "1310481956000+0200"
final String epochTime = fromAPI.substring(0, fromAPI.indexOf("+"));
final String timeZoneOffSet = fromAPI.substring(fromAPI.indexOf("+"), fromAPI.size());
Date date = new Date(Long.parseLong(epochTime));
Notice i'm not doing anything with the time zone (if that's what it is). You'll have to deal with that but this should get you on the right path.
tl;dr
Instant.ofEpochMilli(
java.lang.Long.parseLong( "1310481956000" )
).atOffset( ZoneOffset.of( "+0200" ) )
Using java.time
The accepted Answer is correct but outdated. The modern way to handle this is through the java.time classes.
The input is ambiguous. Is it a count from the Unix epoch reference date-time of first moment of 1970 in UTC 1970-01-01T00:00:00:Z and then adjusted by two hours ahead of UTC? If so, this example code seen here works.
First parse that input number as a Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Extract the first portion of your string and parse as a long.
long millisSinceEpoch = java.lang.Long.parseLong( "1310481956000" );
Instant instant = Instant.ofEpochMilli( millisSinceEpoch );
instant.toString(): 2011-07-12T14:45:56Z
Extract the last portion of your string and parse as a ZoneOffset.
ZoneOffset offset = ZoneOffset.of( "+0200" );
Apply the offset to the Instant to get an OffsetDateTime.
OffsetDateTime odt = instant.atOffset( offset );
odt.toString(): 2011-07-12T16:45:56+02:00
Note that an offset-from-UTC is not a time zone. A zone is an offset plus a set of rules for handling anomalies such as Daylight Saving Time (DST).
Avoid java.util.Date whenever possible. But if you must use one, you can convert to/from java.time. Look to new conversion methods added to the old classes.
java.util.Date d = java.util.Date.from( odt.toInstant() );
d.toString(): Tue Jul 12 14:45:56 GMT 2011
See live code at IdeOne.com covering this entire example.
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.