How to remove milliseconds from LocalTime in java 8 - java

Using the java.time framework, I want to print time in format hh:mm:ss, but LocalTime.now() gives the time in the format hh:mm:ss,nnn. I tried to use DateTimeFormatter:
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_TIME;
LocalTime time = LocalTime.now();
String f = formatter.format(time);
System.out.println(f);
The result:
22:53:51.894
How can I remove milliseconds from the time?

Edit: I should add that these are nanoseconds not milliseconds.
I feel these answers don't really answer the question using the Java 8 SE Date and Time API as intended. I believe the truncatedTo method is the solution here.
LocalDateTime now = LocalDateTime.now();
System.out.println("Pre-Truncate: " + now);
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
System.out.println("Post-Truncate: " + now.truncatedTo(ChronoUnit.SECONDS).format(dtf));
Output:
Pre-Truncate: 2015-10-07T16:40:58.349
Post-Truncate: 2015-10-07T16:40:58
Alternatively, if using Time Zones:
LocalDateTime now = LocalDateTime.now();
ZonedDateTime zoned = now.atZone(ZoneId.of("America/Denver"));
System.out.println("Pre-Truncate: " + zoned);
DateTimeFormatter dtf = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
System.out.println("Post-Truncate: " + zoned.truncatedTo(ChronoUnit.SECONDS).format(dtf));
Output:
Pre-Truncate: 2015-10-07T16:38:53.900-06:00[America/Denver]
Post-Truncate: 2015-10-07T16:38:53-06:00

cut to minutes:
localTime.truncatedTo(ChronoUnit.MINUTES);
cut to seconds:
localTime.truncatedTo(ChronoUnit.SECONDS);
Example:
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
LocalTime.now()
.truncatedTo(ChronoUnit.SECONDS)
.format(DateTimeFormatter.ISO_LOCAL_TIME);
Outputs 15:07:25

Just create the DateTimeFormatter explicitly:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss", Locale.US);
LocalTime time = LocalTime.now();
String f = formatter.format(time);
System.out.println(f);
(I prefer to explicitly use the US locale, to make it clear that I don't want anything from the default format locale.)

Use this in your first line
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");

Try to use patterns defined here: http://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
For example:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd HH. mm. ss");
String text = date.toString(formatter);

You can so it simply by using regex on the string:
String f = formatter.format(time).replaceAll("\\.[^.]*", "");
This deletes (by replacing with blank) the last dot and everything after.

Related

Parse time from string that contains weekname and time

I'm trying to parse only time ignoring weekday from the string with the following format: "Monday 5AM"
Here is my code:
String dateTxt = "Monday 5AM";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ha");
LocalTime lt = LocalTime.parse(dateTxt, formatter);
It throws an exception:
java.time.format.DateTimeParseException: Text 'Saturday 1AM' could not be parsed
How to parse only time from that string?
You need to change the format to
"EEEE ha"
I would also recommend to set the Locale so you have the right language and that it supports AM/PM
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEEE ha", Locale.ENGLISH);
I see the question has been edited now, if you only want the time you can extract or format that from the parse LocalTime object
LocalTime lt = LocalTime.parse(dateTxt, formatter);
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("h a", Locale.ENGLISH);
System.out.println(lt);
System.out.println(lt.format(formatter2));
05:00
5 AM
If we want to ignore the day then we can use following patterns:
[ optional section start
] optional section end
This has different behavior while parsing and formatting. Note: the same pattern has been used for parsing and formatting in following code.
String dateTxt = "Monday 5AM";
//for parsing day of week is ignored
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("[EEEE ]ha", Locale.ENGLISH);
LocalTime lt = LocalTime.parse(dateTxt, formatter);
System.out.println(lt + " - parsed local time ");
//in case of formatting if data is not available
//then the field won't be in output
System.out.println(lt.format(formatter) + " -local time with optnal day in format.");
//the day is available so it will be there in output
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt.format(formatter) + " -local date time with optnal day in format");
Output:
05:00 - parsed local time
5AM -local time with optnal day in format.
Saturday 2PM -local date time with optnal day in format
For formatting if the data is not available then that won't be in output.
If you are only interested in the time, why not just extract that part from dateTxt and parse that part only.
String dateTxt = "Monday 5AM";
DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
DateTimeFormatter fmtr = dtfb.appendValue(ChronoField.CLOCK_HOUR_OF_AMPM)
.appendText(ChronoField.AMPM_OF_DAY, TextStyle.SHORT)
.toFormatter(Locale.ENGLISH);
String timeTxt = dateTxt.split(" ")[1];
System.out.println(LocalTime.parse(timeTxt, fmtr));

DateTimeParseException: Text '2020-04-01T08:53:47.000+02:00 00:00' could not be parsed, unparsed text found at index 29

Getting a DateTimeParseExcpetion when trying to convert the String 2020-04-01T08:53:47.000+02:00 00:00
String date = "2020-04-01T08:53:47.000+02:00 00:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSz");
parsedDate = LocalDateTime.parse(date,formatter).toString();
System.out.println(parsedDate);
Your pattern is not the same as your String. Check the last part where is 000+02:00 00:00.
Your pattern is: SSSz
If you try this:
String date = "2020-04-01T08:53:47.000";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
It will works because your date is like your pattern. Note that every number in the date is into pattern too.
But for your date there is an empty space what no make sense, so removing it, the code works perfectly.
String date = "2020-04-01T08:53:47.000+02:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSz");
Output:
2020-04-01T08:53:47
Note that z is the local time and means "zero hour offset" or "Zulu time" (UTC) and you can use Locale.
The 00:00 at the end of your date-time string doesn't make sense to me. Parse the date-time string after stripping that.
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDate = "2020-04-01T08:53:47.000+02:00 00:00";
strDate = strDate.substring(0, strDate.lastIndexOf(' '));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSz", Locale.ENGLISH);
LocalDateTime parsedDate = LocalDateTime.parse(strDate, formatter);
System.out.println(parsedDate);
OffsetDateTime odt = OffsetDateTime.parse(strDate);
System.out.println(odt);
System.out.println(odt.getOffset());
}
}
Output:
2020-04-01T08:53:47
2020-04-01T08:53:47+02:00
+02:00
Note: You can parse your date-time string (after striping 00:00 from the end of it) to OffsetDateTime in order to preserve the zone-offset information.
Use the built-in formatter
The built-in DateTimeFormatter.ISO_OFFSET_DATE_TIME matches the part of your string that we can understand. And it can parse just that part and ignore the rest.
String date = "2020-04-01T08:53:47.000+02:00 00:00";
ParsePosition pp = new ParsePosition(0);
OffsetDateTime odt = OffsetDateTime.from(
DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(date, pp));
System.out.println("Date and time: " + odt);
System.out.println("Unparsed text: " + date.substring(pp.getIndex()));
Output:
Date and time: 2020-04-01T08:53:47+02:00
Unparsed text: 00:00
Since your string contains an offset from UTC, OffsetDateTime is the correct class to parse into. If we used LocalDateTIme, the offset would be ignored, and we would end up not knowing at which offset the time was to be interpreted, that is, we could not know which point in time it was. With OffsetDateTime the point in time is unambiguous. If you want to convert to the time in your own time zone, convert to ZonedDateTime (still not LocalDateTime).
ZonedDateTime timeInMyTimeZone = odt.atZoneSameInstant(ZoneId.systemDefault());
System.out.println("Date and time: " + timeInMyTimeZone);
Example output:
Date and time: 2020-04-01T11:53:47+05:00[Asia/Aqtobe]
Links
Documentation links:
DateTimeFormatter.ISO_OFFSET_DATE_TIME.
The two-arg DateTimeFormatter.parse​(CharSequence, ParsePosition) that I used.

use pattern with #JsonFormat for java.time.Instant. Do not want to manually write code for it and use annotations [duplicate]

I'm trying to format an Instant to a String using the new Java 8 Date and Time API and the following pattern:
Instant instant = ...;
String out = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(instant);
Using the code above I get an exception which complains about an unsupported field:
java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
at java.time.Instant.getLong(Instant.java:608)
at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
...
Time Zone
To format an Instant a time-zone is required. Without a time-zone, the formatter does not know how to convert the instant to human date-time fields, and therefore throws an exception.
The time-zone can be added directly to the formatter using withZone().
DateTimeFormatter formatter =
DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT )
.withLocale( Locale.UK )
.withZone( ZoneId.systemDefault() );
If you specifically want an ISO-8601 format with no explicit time-zone
(as the OP asked), with the time-zone implicitly UTC, you need
DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.from(ZoneOffset.UTC))
Generating String
Now use that formatter to generate the String representation of your Instant.
Instant instant = Instant.now();
String output = formatter.format( instant );
Dump to console.
System.out.println("formatter: " + formatter + " with zone: " + formatter.getZone() + " and Locale: " + formatter.getLocale() );
System.out.println("instant: " + instant );
System.out.println("output: " + output );
When run.
formatter: Localized(SHORT,SHORT) with zone: US/Pacific and Locale: en_GB
instant: 2015-06-02T21:34:33.616Z
output: 02/06/15 14:34
public static void main(String[] args) {
DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneId.systemDefault());
System.out.println(DATE_TIME_FORMATTER.format(new Date().toInstant()));
}
DateTimeFormatter.ISO_INSTANT.format(Instant.now())
This saves you from having to convert to UTC. However, some other language's time frameworks may not support the milliseconds so you should do
DateTimeFormatter.ISO_INSTANT.format(Instant.now().truncatedTo(ChronoUnit.SECONDS))
The Instant class doesn't contain Zone information, it only stores timestamp in milliseconds from UNIX epoch, i.e. 1 Jan 1070 from UTC.
So, formatter can't print a date because date always printed for concrete time zone.
You should set time zone to formatter and all will be fine, like this :
Instant instant = Instant.ofEpochMilli(92554380000L);
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.UK).withZone(ZoneOffset.UTC);
assert formatter.format(instant).equals("07/12/72 05:33");
assert instant.toString().equals("1972-12-07T05:33:00Z");
Instants are already in UTC and already have a default date format of yyyy-MM-dd. If you're happy with that and don't want to mess with time zones or formatting, you could also toString() it:
Instant instant = Instant.now();
instant.toString()
output: 2020-02-06T18:01:55.648475Z
Don't want the T and Z? (Z indicates this date is UTC. Z stands for "Zulu" aka "Zero hour offset" aka UTC):
instant.toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.663763
Want milliseconds instead of nanoseconds? (So you can plop it into a sql query):
instant.truncatedTo(ChronoUnit.MILLIS).toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.664
etc.
Or if you still want to use formatter created from pattern
you can just use LocalDateTime instead of Instant:
LocalDateTime datetime = LocalDateTime.now();
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(datetime)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String text = date.toString(formatter);
LocalDate date = LocalDate.parse(text, formatter);
I believe this might help, you may need to use some sort of localdate variation instead of instant

SimpleDateFormat parsing results are odd

I want to parse dates from a filesystem and get them in this format:
2013-07-29 14:49:53.813588954 +0200
Therefore my pattern looks like this
yyyy-MM-dd HH:mm:ss.SSSSSSSSS Z
And finally my code:
String rawDate = "2013-07-29 14:49:53.813588954 +0200";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSSSS Z");
Date date = sdf.parse(rawDate);
SimpleDateFormat out = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String parsedDate = out.format(date);
System.out.println(rawDate + " -> " + parsedDate);
But my output looks like this:
2013-07-29 14:49:53.813588954 +0200 -> 2013-08-08 00:49:41.000000954 +0200
I even tried with setLenient(false) but then I got a ParseException.
You've parsed 813588954 as a number of milliseconds - that's over 9 days, and it's being added to 2013-07-29 14:49:53.
Basically, SimpleDateFormat doesn't handle parsing nanoseconds, and java.util.Date only supports millisecond precision anyway.
If you can possibly use Java 8, I'd recommend using java.time for everything - don't use java.util.Date at all. If you can use java.time for parsing but have to use java.util.Date for the rest, that will at least help.
If you can't use Java 8 at all, I'd suggest manually modifying the string to truncate the nanoseconds to milliseconds and then parse with SimpleDateFormat using a pattern that uses .SSS.
Parsing nanoseconds is supported by Java 8's DateTimeFormatter. For this you need to update your pattern:
String rawDate = "2013-07-29 14:49:53.813588954 +0200";
DateTimeFormatter rawDateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.nnnnnnnnn Z");
ZonedDateTime zonedDateTime = ZonedDateTime.parse(rawDate, rawDateFormatter);
System.out.println(zonedDateTime); // prints 2013-07-29T14:49:53.813588954+02:00
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
System.out.println(zonedDateTime.format(formatter)); // prints 2013-07-29 14:49
Because 53.813588954 means 53 seconds and 813588954 milliseconds and 813588954 milliseconds is around 9 days. When doing the formatting on your second output (i.e. parsedDate), Java automatically rounded up by the sequence of seconds -> minutes -> hours -> days -> months -> years.

Java get UTC time

I want to get the time in UTC time zone. So I wrote the code:
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Date;
public class RegularSandbox {
public static void main(String[] args) {
ZonedDateTime utc = ZonedDateTime.now(ZoneOffset.UTC);
System.out.println("DATETIME = " + Date.from(utc.toInstant()));
}
}
The problem is the output shows me the time in PST (my local timezone). I need it to output the time in UTC so I can store it inside of my databases.
System.out.println("DATETIME = " + utc.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
You do too much when trying to convert to old java.util.Date. And then you implicitly use its method toString() which should be well known for the observed behaviour to print the instant always in your system timezone.
But printing in UTC timezone is extremely simple, not even a formatter is needed if you can cope with ISO-8601-notation:
ZonedDateTime utc = ZonedDateTime.now(ZoneOffset.UTC);
System.out.println("DATETIME = " + utc.toInstant());
// output: DATETIME = 2015-12-30T15:01:18.483Z (Instant is always printed with UTC offset)
System.out.println("DATETIME = " + utc);
// output: DATETIME = 2015-12-30T15:01:57.611Z (the same because you
// have explicitly set the UTC Offset when constructing the ZonedDateTime)
You see, the behaviour of toString() of the new Java-8 classes Instant and ZonedDateTime is much clearer and is always in ISO-format. No need for a confusing conversion to Date.
About specialized formatters, you will only need one if you intend to deviate from ISO-8601-format - maybe using localized month names or extra printing of weekdays etc. Example in US-style:
System.out.println(
"DATETIME = "
+ utc.format(DateTimeFormatter.ofPattern("MM/dd/uuuu h:mm:ss a xxx")));
// output: DATETIME = 12/30/2015 3:14:50 PM +00:00
Note that the answer of #LowLevel uses a wrong pattern. If you leave out the symbol a (AM/PM-marker) then you should not choose the half-day-hour-symbol h but H (24-hour-format). And the timezone or offset symbol (here x) is crucial because otherwise the printed datetime will not be automatically recognized as being in UTC timezone.
ZonedDateTime utc = ZonedDateTime.now(ZoneOffset.UTC);
final SimpleDateFormat sdf = new SimpleDateFormat("EEE, MMM d, yyyy hh:mm:ss a z"); // you can specify format that you want to get
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("UTC time: " + sdf.format(utc));
private Calendar getUTCTime(){
Calendar calendar = Calendar.getInstance();
// Assuming your time is in utc + 8
calendar.add(Calendar.HOUR, -8);
return calendar;
}
I suggest you to use Joda-Time.
DateTime dt = new DateTime(DateTimeZone.UTC);

Categories

Resources