Jackson deserialize Joda DateTime from Unix format - java

When deserializing from JSON I have dates that are written in Unix Epoch time (/Date(1379542610387+1000)/).
I understand that is it pretty standard to serialize dates in Json this way, however how can I get this value deserialized into a Joda DateTime?
When jackson see's a value like this it spits out:
Invalid format: "/Date(1379542610387+1000)/"

private static final Pattern pat = Pattern.compile("/Date\\((\d+)[\\+\\-](\\d+)\\)/");
...
String data = "/Date(1379542610387+1000)/";
Matcher m = pat.matcher(data);
if (m.matches())
{
long time = Long.valueOf(m.group(1));
int offset = Integer.valueOf(m.group(2));
System.out.printf("time=%d offset=%d\n",time,offset);
}
else
// not a date in the recognized format ...

Related

Convert String to LocalDateTime Java 8

I'm trying to convert the following String into a LocalDateTime:
String dateStr = "2020-08-17T10:11:16.908732";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.nnnnnn");
LocalDateTime dateTime = LocalDateTime.parse(dateStr, format);
But I'm hitting the following error:
java.time.format.DateTimeParseException: Text '2020-08-17T10:11:16.908732' could not be parsed at index 10
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
at java.time.LocalDateTime.parse(LocalDateTime.java:492)
Can anyone please help to advise how I should be correctly formatting the string into a LocalDateTime?
Many thanks
You don't need to specify a DateTimeFormatter in this case because the default one will be used if you don't pass one at all:
public static void main(String[] args) {
String dateStr = "2020-08-17T10:11:16.908732";
// the following uses the DateTimeFormatter.ISO_LOCAL_DATE_TIME implicitly
LocalDateTime dateTime = LocalDateTime.parse(dateStr);
System.out.println(dateTime);
}
That code will output 2020-08-17T10:11:16.908732.
If you are insisting on using a custom DateTimeFormatter, consider the T by single-quoting it in the pattern and don't use nanosecond parsing (n) for parsing fractions of second (S), the result might be wrong otherwise.
Do it like this:
public static void main(String[] args) {
String dateStr = "2020-08-17T10:11:16.908732";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS");
LocalDateTime dateTime = LocalDateTime.parse(dateStr, format);
System.out.println(dateTime);
}
with the same output as above.
Note:
The result of using the pattern "yyyy-MM-dd'T'HH:mm:ss.nnnnnn" would not be equal to the parsed String, instead, it would be
2020-08-17T10:11:16.000908732
For your given DateTime string pattern should be updated "yyyy-MM-dd'T'HH:mm:ss.nnnnnn".
So the code should be like :
String dateStr = "2020-08-17T10:11:16.908732";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.nnnnnn");
LocalDateTime dateTime = LocalDateTime.parse(dateStr, format);
For more details around it you can refer JavaDoc.
Along that in your given input DateTime it's using 6 digits, so it can't be nano seconds. Because nano is 1/1000000000. So it will have at least 9 digits. So the correct format rather should be second fraction with 6 digits as "yyyy-MM-dd'T'HH:mm:ss.SSSSSS".
End Results comparison:
With Pattern : "yyyy-MM-dd'T'HH:mm:ss.nnnnnn"
System.out.println(LocalDateTime.parse("2020-08-17T10:11:16.908732", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.nnnnnn")));
Output : 2020-08-7T10:11:16.000908732
With Pattern : "yyyy-MM-dd'T'HH:mm:ss.SSSSSS"
System.out.println(LocalDateTime.parse("2020-08-17T10:11:16.908732", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS")));
Output : 2020-08-7T10:11:16.908732

Catering for multiple date formats when converting date formats using Joda time

Below code converts a date format from "yyyy-MM-dd'T'HH:mm:ss" to "MM/dd/yyyy" .
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class TestDate {
public static void main(String[] args) {
DateTimeFormatter parser = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");
DateTime dateTime = parser.parseDateTime("2014-05-19T23:59:59");
DateTimeFormatter formatter = DateTimeFormat.forPattern("MM/dd/yyyy");
System.out.println(formatter.print(dateTime)+"\n");
dateTime = parser.parseDateTime("2014-06-09T03:00:23.67");
formatter = DateTimeFormat.forPattern("MM/dd/yyyy");
System.out.println(formatter.print(dateTime));
}
An exception is thrown for "2014-06-09T03:00:23.67" :
Exception in thread "main" java.lang.IllegalArgumentException: Invalid format: "2014-06-09T03:00:23.67" is malformed at ".67"
at org.joda.time.format.DateTimeFormatter.parseDateTime(DateTimeFormatter.java:899)
at TestDate.main(TestDate.java:16)
I need to be able to cater for other possibilities also such as :
2014-05-27T03:00:32.613
I just require the "MM/dd/yyyy" part of the date, everything subsequent to that can be ignored. Do I need to anticipate every date format explained at Using Joda Date & Time API to parse multiple formats
Or can a wildcard be used which ignores everything after a certain pattern. Something like :
DateTimeFormatter parser = DateTimeFormat.forPattern("yyyy-MM-dd%");
Or I could parse the string and split at the 'T' section of the date time, just using the value that appears before 'T', though this seems unclean....
Or is there an alternative method ?
Update :
Since time is not required, instead of using :
String strDate = "2014-05-19T23:59:59";
DateTime dateTime = parser.parseDateTime(strDate);
will use :
String strDate = "2014-05-19T23:59:59";
DateTime dateTime = parser.parseDateTime(strDate.substring(0, 10));
Which will just parse 2014-05-19 part of String, this will cater for multiple time formats.
You can extract date from date-time (format yyyy-MM-dd%) string in next ways:
1) Using String::split
String dateTime = "2014-05-19T23:59:59";
String date = dateTime.split("T")[0];
2) Using regexp
Pattern pattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
Matcher matcher = pattern.matcher(dateTime);
if (matcher.find())
{
System.out.println(matcher.group());
}
Also you can change format yyyy-MM-dd% to MM/dd/yyyy with regexp:
String dateTime = "2014-05-19T23:59:59";
// pattern for 'yyyy-MM-dd%'
Pattern pattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2}).+");
Matcher matcher = pattern.matcher(dateTime);
if (matcher.matches())
{
// date in format 'MM/dd/yyyy'
String dateInNewFormat = String.format("%s/%s/%s",
matcher.group(2), matcher.group(3), matcher.group(1));
}

Convert java date to json date

Please some one help me on this
I have a simple Date object like:
Date dt = new Date();
I want to convert it to json date format like:
"\/Date(928164000000-0400)\/"
How to do that.
Use
Date dt = new Date();
"\/Date(" + dt.getTime() + "-0400)\/"
You probably need to parse the getTime() first, depending on what your current date format is.
This is using com.google.gson.*
final JsonSerializer<Date> dateSerialize = new JsonSerializer<Date>()
{
#Override
public JsonElement serialize(final Date src,
final Type typeOfSrc,
final JsonSerializationContext context)
{
final String dateString = "Date(" + src.getTime() + "-" + src.getTimezoneOffset()+")";
return new JsonPrimitive(dateString);
}
};
Gson gson = GsonBuilder().registerTypeAdapter(Date.class, dateSerialize)
.create();
Date dt = new Date();*
gson.toJson(dt);
There isn't really a Date format in JSON, only some not universal conventions.
This being said, your "date" is in two parts :
a number of milliseconds since epoch. You can get this in UTC using the getTime() method
a time zone offset
But a java Date (contrary to a calendar), just like a javascript one, doesn't contain the time offset (getTimezoneOffset() is deprecated). So you have to decide which one you want to use. Or you might, as I would do, simply send the UTC timestamp with a zero offset :
var jsonDateUTC = "Date("+javaDate.getTime()+"-0000)";

Json Date to Java Date and back to Json Date

I looked through all possible answer here but I am having hard time to figure this thing out.
I have Json date in a String. I want to convert into a Java Date without losing time.
Also I would like to convert from Java Date to Json Date string.
Here what I have.
String jsonDateString = "/Date(1295157600000-0600)/";
There are 2 parts in your time : the local time in milliseconds, and the offset in hours and minutes. You have to parse them and "add" them to get the milliseconds UTC.
You may do it using this function :
private static Pattern p = Pattern.compile("\\((\\d+)([+-]\\d{2})(\\d{2})\\)");
public static Date jd2d(String jsonDateString) {
Matcher m = p.matcher(jsonDateString);
if (m.find()) {
long millis = Long.parseLong(m.group(1));
long offsetHours = Long.parseLong(m.group(2));
long offsetMinutes = Long.parseLong(m.group(3));
if (offsetHours<0) offsetMinutes *= -1;
return new Date(
millis
+ offsetHours*60l*60l*1000l
+ offsetMinutes*60l*1000l
);
}
return null;
}
To make "back" a JSON date, I would simply encode the UTC time :
String jsonDate = "/Date("+date.getTime()+"+0000)/";

java date format incompatible with xquery xs:date format, how to fix?

In java, when using SimpleDateFormat with the pattern:
yyyy-MM-dd'T'HH:mm:ss.SSSZ
the date is outputted as:
"2002-02-01T18:18:42.703-0700"
In xquery, when using the xs:dateTime function, it gives the error:
"Invalid lexical value [err:FORG0001]"
with the above date. In order for xquery to parse properly, the date needs to look like:
"2002-02-01T18:18:42.703-07:00" - node the ':' 3rd position from end of string
which is based on the ISO 8601, whereas Java date is based on the RFC 822 standard.
I would like to be able to easily specify the timezone in Java so that it will output the way that xquery wants.
Thanks!
OK, the linked to forum post DID help, thank you. I did however find a simpler solution, which I include below:
1) Use Apache commons.lang java library
2) Use the following java code:
//NOTE: ZZ on end is not compatible with jdk, but allows for formatting
//dates like so (note the : 3rd from last spot, which is iso8601 standard):
//date=2008-10-03T10:29:40.046-04:00
private static final String DATE_FORMAT_8601 = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ";
DateFormatUtils.format(new Date(), DATE_FORMAT_8601)
Great find regarding commons.lang.java! You can even save yourself from creating your own format string by doing the following:
DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(new Date());
Well, I did run into a problem - it doesn't appear to me (and I could be wrong) that there was any way to convert from and ISO string that DateUtils (from apache commons lang) creates, back to a date!
ie. apache commons will format it the way I would like, but not convert it back to a date again
So, I switched to JodaTime, and its much easier since its based on ISO8601 - here is the code:
public static void main(String[] args) {
Date date = new Date();
DateTime dateTime = new DateTime(date);
DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
String dateString = fmt.print(dateTime);
System.out.println("dateString=" + dateString);
DateTime dt = fmt.parseDateTime(dateString);
System.out.println("converted date=" + dt.toDate());
}
Try this:
static public String formatISO8601(Calendar cal) {
MessageFormat format = new MessageFormat("{0,time}{1,number,+00;-00}:{2,number,00}");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
df.setTimeZone(cal.getTimeZone());
format.setFormat(0, df);
long zoneOff = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET) / 60000L;
int zoneHrs = (int) (zoneOff / 60L);
int zoneMins = (int) (zoneOff % 60L);
if (zoneMins < 0)
zoneMins = -zoneMins;
return (format.format(new Object[] { cal.getTime(), new Integer(zoneHrs), new Integer(zoneMins) }));
}

Categories