I have dates in potentially 2 formats:
2013-07-03T14:30:38Z
2013-07-03T14:30:38.000000Z
I want to axe the .00000
if it exists
I got this far, to remove everything after the '.'
time.replaceFirst("^(.*?)\\b\\..*$"
, "$1");
result: 2013-07-03T14:30:38
Problem is, I still need the 'Z
' .. how can I keep the Z
?
so I'm not entirely sure if there will always be 6 0s (if the string contains the nanoseconds) or if there can be a variable number of 0s...
I'm using java but didn't want to tag it as java since it's basically just pure regex
I should correct the terminology in the Question: You (apparently) have strings in a certain format, not "dates". Do not confuse date-time values with their String representations.
Just as "$12.34" is not a number, it is a string representation of a number with a certain format applied. That string can be parsed into a number.
This concept is the essence of the following code. We parse a string to instantiate a date-time object, then use that date-time object to generate a new string representation.
Java 8 and later has a new java.time framework built-in (Tutorial). You could use that for parsing a string as a date-time value, and then generating a new string representation in any format you desire. Here's some code if you want to explore this as an alternative to regex.
Both of your possible formats are nearly in ISO 8601 format. Strictly speaking the standard expects only millisecond resolution (3 decimal places) as far as I know, but the java.time framework extends that to nanosecond (up to 9 decimal places).
The java.time framework uses ISO 8601 as its default when parsing and generating strings. So you need not specify a formatter pattern, and instead can use one of the several predefined formatters aimed at ISO 8601 standard formats.
An Instant
object represents a moment on the timeline in UTC. You could assign a particular time zone to get a ZonedDateTime
, but not needed for this particular Question. This class can parse your input strings by default.
String input = "2013-07-03T14:30:38.123456789Z";
Instant instant = Instant.parse( input );
After parsing we have an instant
object in hand. From there we can effectively truncate the fractions of a second by calling the with
method to change the fractional second to zero. Technically speaking we are not changing the fractional seconds, as java.time uses immutable objects. A new object is created based on the values of the original.
Instant instantTruncated = instant.with( ChronoField.NANO_OF_SECOND , 0 );
Lastly we use the predefined formatter, DateTimeFormatter.ISO_INSTANT
. This formatter automatically suppresses the fractional zero from the generated string in groups of three digits where the value is zero. So …7.12
prints as …7.120
, …7.1234
as …7.123400
, and …7.0
as …7
. That last value is fits our needs.
DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT;
String output = formatter.format( instantTruncated );
The toString
method on Instant
uses the formatter DateTimeFormatter.ISO_INSTANT
by default. So technically we could shorten the code to just call toString
. But I want to show explicitly how a formatter is involved.
Dump to console.
System.out.println( "instant: " + instant );
System.out.println( "instantTruncated: " + instantTruncated );
System.out.println( "output: " + output );
When run.
instant: 2013-07-03T14:30:38.123456789Z
instantTruncated: 2013-07-03T14:30:38Z
output: 2013-07-03T14:30:38Z
We can assign a time zone to that Instant to get a 'ZonedDateTime`.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instantTuncated , zoneId);
Simply add the Z
back inside:
time.replaceFirst( "^(.*?)\\b\\..*$", "$1Z");
And alternative would be to capture everything until you encounter the period character (.
):
time.replaceFirst( "^([^.]+).*(Z)$", "$1$2");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With