SAP PI UDF to convert date without time to datetime ISO8601 string - java

I need to write a java function for SAP PI which returns a string for my XML mapping in the format: yyyy-MM-dd T HH:mm:ss (e.g., 2018-08-15T00:00:00) even when my source field is just a date field without time (e.g., 2018-08-15).
I've tried the SimpleDateFormat Java class but I can't get it to work. Is there a simple way of doing this?
In the suggested posts (answers / duplicates / links) I couldn't find what I was looking for. Guess I didn't make myself clear enough describing the problem but the thing was I'm getting the date from a source XML (SAP PO) and I need to convert it to an ISO 8601 date in the target XML.
Thanks to Ole I came up with the following 'beginners' function (for completeness):
public String DH_FormatDateTimeStringB(String ndate, String npattern, Container container) throws StreamTransformationException{
//This function gets a date from the IDOC and returns it as a datetime string in ISO 8601 (ISO 8601 Representation of dates and times
//in information interchange required. Ex: npattern = "yyyy-MM-dd")
DateTimeFormatter formatterDate = DateTimeFormatter.ofPattern(npattern);
LocalDate date = LocalDate.parse(ndate, formatterDate);
//Convert date to datetime
LocalDateTime localDateTime1 = date.atStartOfDay();
//System.out.println(localDateTime1.toString());
return localDateTime1.toString();
}
Since it now only takes a date without time it might the 'StartOfDay' will do. Maybe I adjust it later on to see if there's a time part in the string.
Thnx all for helping out!

String dateStringFromSapPo = "2018-08-15";
LocalDate date = LocalDate.parse(dateStringFromSapPo);
LocalDateTime dateTime = date.atStartOfDay();
String dateTimeStringForSapPi = dateTime.toString();
System.out.println("String for SAP PI: " + dateTimeStringForSapPi);
This prints:
String for SAP PI: 2018-08-15T00:00
It hasn’t got seconds, but conforms with the ISO 8601 standard, so should work in your XML and SAP. If it doesn’t, you will need to use an explicit formatter:
DateTimeFormatter dateTimeFormatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss");
String dateTimeStringForSapPi = dateTime.format(dateTimeFormatter);
Now the seconds come out too:
String for SAP PI: 2018-08-15T00:00:00
As an aside, it worries me a bit to give you a date-time string without time zone or offset. It’s not a point in time and to interpret it as one, SAP will have to assume a time zone. Only if you are sure it picks the intended one, you’re fine. If not, I’m sorry that I cannot tell you the solution.
Link: Oracle tutorial: Date Time explaining how to use java.time

Related

Obtaining the ISO 8601 date format, e.g.: 2009-06-15T13:45:30

How do you format your date in ISO 8601? E.g.: 2009-06-15T13:45:30
Is there a standard way of generating it from Java without having to create a DateTimeFormatter with a letter pattern?
I see it used in MS documentation:
Standard Date and Time Format Strings
I think this is the commonly referred to as "ISO" date.
Documented in wikipedia], giving examples such as:
Date: 2017-02-21
Combined date and time in UTC: 2017-02-21T10:26:42+00:00
2017-02-21T10:26:42Z
20170221T102642Z
The one thing to be clear: your examples go without any time zone information; so they should be assumed to be "local time".
In this String, T is just Time component in a standard ISO 8601 date time string represented as <date>T<time>. Wikipedia has a detailed page about this standard format.
In java, you can do this to use it
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
I have used GMT here just for example. You can set the time zone according to your need. To get more information about TimeZone here is the docs link
ISO-8601
A single point in time can be represented by concatenating a complete date expression, the letter T as a delimiter, and a valid time expression. For example, "2007-04-05T14:30".
The format of such date is a local date time of ISO 8601, without the time-zone.1 According to Wikipedia, date and time expressed according to ISO 8601 are:
Date: 2017-02-21
Combined date and time in UTC: 2017-02-21T12:34:46+00:00
2017-02-21T12:34:46Z
20170221T123446Z
...
There're several ways to create strings with such format in Java. In Java 8, the easiest way is to use the built-in parsing pattern of LocalDateTime. The reason why I don't use ZonedDateTime is that the time-zone of this date is unknown.
// str -> date
LocalDateTime d = LocalDateTime.parse("2009-06-15T13:45:30");
// date -> str
String text = d.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
1 ISO 8601: Time zone designators
Easy ways to obtain ISO 8601 in Java:
static void time() {
final DateTimeFormatter fmt = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
OffsetDateTime.now().truncatedTo(ChronoUnit.SECONDS).format(fmt);
Instant.now().atOffset(ZoneOffset.ofHours(1)).truncatedTo(ChronoUnit.SECONDS).format(fmt);
Instant.now().atOffset(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS).format(fmt);
OffsetDateTime.parse("2007-12-03T10:15:30+01:00").format(fmt);
LocalDateTime.parse("2009-06-15T13:45:30").format(fmt);
}

Converting a time String to ISO 8601 format

I am trying to create a String in a format like 2015-08-20T08:26:21.000Z
to 2015-08-20T08:26:21Z
I know it can be done with some String splitting techniques, but i am wondering if there is an elegant solution for that (with minimal code changes).
Both of the above are time strings, the final one which i need is Date in ISO 8601 . https://www.rfc-editor.org/rfc/rfc3339#section-5.6
I have tried a few similar questions like converting a date string into milliseconds in java but they dont actually solve the purpose.
Also tried using :
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
String nowAsString = df.format(new Date());
But it still does not do any String to String conversions. Getting the following error:
23:04:13,829 WARN [RuntimeExceptionMapper] caught RuntimeException: {}: java.lang.IllegalArgumentException: Cannot format given Object as a Date
Is there some library which someone can suggest ?
Thanks.
tl;dr
Instant.parse( "2015-08-20T08:26:21.000Z" )
.toString()
2015-08-20T08:26:21Z
Date-Time Formatter
If all you want to do is eliminate the .000, then use date-time objects to parse your input string value, then generate a new string representation of that date-time value in a different format.
ISO 8601
By the way, if that is your goal, the Question’s title make no sense as both strings mentioned in the first sentence are valid ISO 8601 formatted strings.
2015-08-20T08:26:21.000Z
2015-08-20T08:26:21Z
java.time
Java 8 and later has the new java.time package. These new classes supplant the old java.util.Date/.Calendar & java.text.SimpleDateFormat classes. Those old classes were confusing, troublesome, and flawed.
Instant
If all you want is UTC time zone, then you can use the Instant class. This class represents a point along the timeline without regard to any particular time zone (basically UTC).
DateTimeFormatter.ISO_INSTANT
Calling an Instant’s toString generates a String representation of the date-time value using a DateTimeFormatter.ISO_INSTANT formatter instance. This formatter is automatically flexible about the fractional second. If the value has a whole second, no decimal places are generated (apparently what the Question wants). For a fractional second, digits appear in groups of 3, 6, or 9, as needed to represent the value up to nanosecond resolution. Note: this format may exceed ISO 8601 limit of milliseconds (3 decimal places).
Example code
Here is some example code in Java 8 Update 51.
String output = Instant.parse( "2015-08-20T08:26:21.000Z" ).toString( );
System.out.println("output: " + output );
output: 2015-08-20T08:26:21Z
Changing to a fractional second, .08
String output = Instant.parse( "2015-08-20T08:26:21.08Z" ).toString( );
output: 2015-08-20T08:26:21.080Z
If interested in any time zone other than UTC, then make a ZonedDateTime object from that Instant.
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , ZoneId.of( "America/Montreal" ) ) ;
Your format is just not right try this :-
try {
String s = "2015-08-20T08:26:21.000Z";
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
Date d = df.parse(s);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
System.out.println(sdf.format(d));
} catch (ParseException e) {
e.printStackTrace();
}
Conversion of a date String of unknown formatting into a date String that uses known formatting can be accomplished using two DateFormat objects- one dynamically configured to parse the format of the input String, and one configured to generate the formatted output String. For your situation the input String formatting is unspecified and must be provided by the caller, however, the output String formatting can be configured to use ISO 8601 formatting without additional input. Essentially, generating an ISO 8601 formatted date String output requires two inputs provided by the caller- a String containing the formatted date and another String that contains the SimpleDateFormat format.
Here is the described conversion as Java code (I deliberately have left out null checks and validations, add these as appropriate for your code):
private String formatDateAsIso8601(final String inputDateAsString, final String inputStringFormat) throws ParseException {
final DateFormat iso8601DateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'", Locale.ENGLISH);
iso8601DateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
final DateFormat inputDateFormatter = new SimpleDateFormat(inputStringFormat, Locale.ENGLISH);
final Date inputDate = inputDateFormatter.parse(inputDateAsString);
return iso8601DateFormatter.format(inputDate);
}
If you want to modify that method please note that SimpleDateFormat is not thread-safe, and that you should not use it from a static context without a workaround for multi-threaded code (ThreadLocal is commonly used to do just such a workaround for SimpleDateFormat).
An additional "gotcha" is the use of a Locale during the construction of the SimpleDateFormat objects- do not remove the Locale configuration. It is not safe to allow the system to choose to use the default Locale because that is user/machine specific. If you do allow it to use the default Locale, you run the risk of transient bugs because your development machine uses a Locale different than the Locale of your end-user. You do not have to use my selected ENGLISH Locale, it is perfectly fine to use a different Locale (you should understand the rules of that Locale and modify the code as appropriate however). Specification of no Locale and utilization of the system default is incorrect however, and likely will lead to many frustrating hours trying to diagnose an elusive bug.
Please understand this solution is not ideal as of Java 8 and the inclusion of the JodaTime based classes, like Instant. I chose to answer using the outdated API's because those were what you seemed concerned with in your question. If you are using Java 8 I strongly urge to learn and utilize the new classes as they are an improvement in almost every conceivable way.

Joda-Time DateTime formatting based on locale

I receive a string date from another system and I know the locale of that date (also available from the other system). I want to convert this String into a Joda-Time DateTime object without explicitly specifying the target pattern.
So for example, I want to convert this String "09/29/2014" into a date object using the locale only and not by hard coding the date format to "mm/dd/yyyy". I cant hard code the format as this will vary depending on the local of the date I receive.
String localizedCalendarDate = DateTimeFormat.shortDate().print(new LocalDate(2014, 9, 29));
// uses in Germany: dd.MM.yyyy
// but uses in US: MM/dd/yyyy
LocalDate date =
DateTimeFormat.mediumDate().withLocale(Locale.US).parseLocalDate("09/29/2014");
DateTime dt = date.toDateTimeAtStartOfDay(DateTimeZone.forID("America/Los_Angeles"));
As you can see, you will also need to know the clock time (= start of day in example) and time zone (US-California in example) in order to convert a parsed date to a global timestamp like DateTime.

How to Convert JavaScript Date to Date in Java?

I need to convert JsDate to java.util.Date. I searched but I couldn't find anything. So could you help me with this problem?
Edit: I do this conversion process on GWT screen. I have Datepicker on screen and it gives me JsDate value when I use it's getValue() method. So I'm supposed to put this value into the property of an object which has Date type.
ObjectName.setDate(PickerName.getValue());
I hope my edit will be more clear.
Edit2:
This line is the solution of my problem:
myObject.setDate(new Date((long) myPicker.getValue().getTime()));
The best way of dates conversion is using time in milliseconds, UTC. Both JS Date object and java.util.Date class support conversion to milliseconds (getTime()) and instantiating from milliseconds (using constructor).
You can create a java.util.Date object from the 'time since epoch' value of the JS Date
javascript
var d = new Date().getTime();
java
// get value from client (ajax, form, etc), and construct in Date object
long valueFromClient = ...
Date date = new Date(valueFromClient);
String formatted = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
If people like me are forced to parse a JS-formatted date string (as the result of (new Date()).toString() in JavaScript), here is the SimpleDateFormat spec I used:
DateFormat jsfmt = new SimpleDateFormat("EE MMM d y H:m:s 'GMT'Z (zz)");
If you have control of the producer of the dates, I concur that using timestamps or at least .toUTCString() is definitely more robust.
You may want this:
java:
String jsDate="2013-3-22 10:13:00";
Date javaDate=new SimpleDateFormat("yy-MM-dd HH:mm:ss").parse(jsDate);
System.out.println(javaDate);
ISO 8601 and java.time
ISO 8601 is the international standard for date and time including date and time formats. About any programming language has support for it, including both JavaScript and Java.
In JavaScript produce a string in ISO 8601 format using Date.toISOString(). We don’t need any formatter.
var d = new Date();
var n = d.toISOString();
console.log(n);
The result is somewhat human readable as long as you remember that it’s in UTC, denoted by the trailing Z.
In Java parse the string using Instant.parse(). We don’t need to specify any formatter here either.
String stringFromJavaScript = "2021-07-12T05:54:03.365Z";
Instant inst = Instant.parse(stringFromJavaScript);
System.out.println(inst);
Output:
2021-07-12T05:54:03.365Z
The question asked for a java.util.Date for the result from a date picker. We should avoid using java.util.Date for this both because despite the name a Date does not represent a date and because the Date class is poorly designed and long outdated. For a date without time of day a LocalDate is appropriate:
LocalDate date = inst.atZone(ZoneId.systemDefault()).toLocalDate();
System.out.println(date);
In my time zone the output was:
2021-07-12
The conversion is time zone dependent and will only be correct if the default time zone of the JVM (or which time zone you pass to atZone()) is the same as used by the date picker.
If you do need a Date for a legacy API not yet upgraded to java.time:
Date oldfashionedDate = Date.from(inst);
System.out.println(oldfashionedDate);
Mon Jul 12 07:54:03 CEST 2021
Links
Wikipedia article: ISO 8601
Oracle tutorial: Date Time explaining how to use java.time.
I would suggest using the DateFormat parse method (doc can be found here). It can parse a string representation of a date and return a java.util.Date.
JS Date --
new Date()
Wed Aug 14 2019 14:54:38 GMT+0530 (India Standard Time)
Java Date --
new Date().toISOString()
"2019-08-14T09:25:50.136Z"

How to format a java.sql Timestamp for displaying?

How do I formate a java.sql Timestamp to my liking ? ( to a string, for display purposes)
java.sql.Timestamp extends java.util.Date. You can do:
String s = new SimpleDateFormat("MM/dd/yyyy").format(myTimestamp);
Or to also include time:
String s = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(myTimestamp);
Use String.format (or java.util.Formatter):
Timestamp timestamp = ...
String.format("%1$TD %1$TT", timestamp)
EDIT:
please see the documentation of Formatter to know what TD and TT means: click on java.util.Formatter
The first 'T' stands for:
't', 'T' date/time Prefix for date and time conversion characters.
and the character following that 'T':
'T' Time formatted for the 24-hour clock as "%tH:%tM:%tS".
'D' Date formatted as "%tm/%td/%ty".
If you're using MySQL and want the database itself to perform the conversion, use this:
DATE_FORMAT(date,format)
If you prefer to format using Java, use this:
java.text.SimpleDateFormat
SimpleDateFormat dateFormat = new SimpleDateFormat("M/dd/yyyy");
dateFormat.format( new Date() );
For this particular question, the standard suggestion of java.text.SimpleDateFormat works, but has the unfortunate side effect that SimpleDateFormat is not thread-safe and can be the source of particularly nasty problems since it'll corrupt your output in multi-threaded scenarios, and you won't get any exceptions!
I would strongly recommend looking at Joda for anything like this. Why ? It's a much richer and more intuitive time/date library for Java than the current library (and the basis of the up-and-coming new standard Java date/time library, so you'll be learning a soon-to-be-standard API).
Use a DateFormat. In an internationalized application, use the format provide by getInstance. If you want to explicitly control the format, create a new SimpleDateFormat yourself.
java.time
I am providing the modern answer. The Timestamp class is a hack on top of the already poorly designed java.util.Date class and is long outdated. I am assuming, though, that you are getting a Timestamp from a legacy API that you cannot afford to upgrade to java.time just now. When you do that, convert it to a modern Instant and do further processing from there.
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
.withLocale(Locale.GERMAN);
Timestamp oldfashionedTimestamp = new Timestamp(1_567_890_123_456L);
ZonedDateTime dateTime = oldfashionedTimestamp.toInstant()
.atZone(ZoneId.systemDefault());
String desiredFormat = dateTime.format(formatter);
System.out.println(desiredFormat);
Output in my time zone:
07.09.2019 23:02:03
Pick how long or short of a format you want by specifying FormatStyle.SHORT, .MEDIUM, .LONG or .FULL. Pick your own locale where I put Locale.GERMAN. And pick your desired time zone, for example ZoneId.of("Europe/Oslo"). A Timestamp is a point in time without time zone, so we need a time zone to be able to convert it into year, month, day, hour, minute, etc. If your Timestamp comes from a database value of type timestamp without time zone (generally not recommended, but unfortunately often seen), ZoneId.systemDefault() is likely to give you the correct result. Another and slightly simpler option in this case is instead to convert to a LocalDateTime using oldfashionedTimestamp.toLocalDateTime() and then format the LocalDateTime in the same way as I did with the ZonedDateTime.
String timeFrSSHStr = timeFrSSH.toString();

Categories

Resources