Java: Adding TimeZone to DateTimeFormatter - java

The LocalDateTime API gives the possibility to add the TimeZone Name by using the key "z" in the formatter. I get an exception adding this key and don't understand why. I'm looking for something like this example '11:59:22 PM GMT' and not '**... UMT+2**'.
My Code:
public class TimeZone
{
public static void main(String[] args)
{
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm:ss a z");
System.out.println(now.format(formatter));
}
}
The Exception:
Exception in thread "main" java.time.DateTimeException: Unable to extract value: class java.time.LocalDateTime
at java.time.format.DateTimePrintContext.getValue(Unknown Source)
at java.time.format.DateTimeFormatterBuilder$ZoneTextPrinterParser.format(Unknown Source)
at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(Unknown Source)
at java.time.format.DateTimeFormatter.formatTo(Unknown Source)
at java.time.format.DateTimeFormatter.format(Unknown Source)
at java.time.LocalDateTime.format(Unknown Source)
at tz.TimeZone.main(TimeZone.java:12)
Here is the DateTimeFormatter API part:
All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters. The following pattern letters are defined:
Symbol Meaning Presentation Examples
------ ------- ------------ -------
G era text AD; Anno Domini; A
u year year 2004; 04
y year-of-era year 2004; 04
D day-of-year number 189
M/L month-of-year number/text 7; 07; Jul; July; J
d day-of-month number 10
Q/q quarter-of-year number/text 3; 03; Q3; 3rd quarter
Y week-based-year year 1996; 96
w week-of-week-based-year number 27
W week-of-month number 4
E day-of-week text Tue; Tuesday; T
e/c localized day-of-week number/text 2; 02; Tue; Tuesday; T
F week-of-month number 3
a am-pm-of-day text PM
h clock-hour-of-am-pm (1-12) number 12
K hour-of-am-pm (0-11) number 0
k clock-hour-of-am-pm (1-24) number 0
H hour-of-day (0-23) number 0
m minute-of-hour number 30
s second-of-minute number 55
S fraction-of-second fraction 978
A milli-of-day number 1234
n nano-of-second number 987654321
N nano-of-day number 1234000000
V time-zone ID zone-id America/Los_Angeles; Z; -08:30
z time-zone name zone-name Pacific Standard Time; PST
O localized zone-offset offset-O GMT+8; GMT+08:00; UTC-08:00;
X zone-offset 'Z' for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15;
x zone-offset offset-x +0000; -08; -0830; -08:30; -083015; -08:30:15;
Z zone-offset offset-Z +0000; -0800; -08:00;
Can anyone see what the problem is?

LocalDateTime has two fields of type LocalDate and LocalTime.
LocalDate has fields day, month, and year.
LocalTime has fields hour, minute, second, and nano.
Nowhere in that is a time zone given. Which is by nature, since the javadoc of LocalDateTime says:
A date-time without a time-zone
So, if the "local" date/time value is already representing a time in UTC, and you want it formatted saying so, you have multiple options:
Change the LocalDateTime to a ZonedDateTime by calling atZone():
System.out.println(time.atZone(ZoneOffset.UTC)
.format(DateTimeFormatter.ofPattern("hh:mm:ss a z")));
Specify an override time zone in the formatter by calling withZone():
System.out.println(time.format(DateTimeFormatter.ofPattern("hh:mm:ss a z")
.withZone(ZoneOffset.UTC)));
Format with a literal Z character:
System.out.println(time.format(DateTimeFormatter.ofPattern("hh:mm:ss a 'Z'")));
All three of the above outputs:
11:59:22 PM Z
Now, if the "local" date/time is really in a different time zone, you can use either of the first two, and just specify the actual zone.
E.g. if time zone is -04:00, use ZoneOffset.ofHours(-4), and you'll get:
11:59:22 PM -04:00
Or if you are in New York, use ZoneId.of("America/New_York"), and you'll get:
11:59:22 PM EDT
If the "local" date/time is for New York, but you want formatted text to be UTC, use both at the same time, i.e.
System.out.println(time.atZone(ZoneId.of("America/New_York"))
.format(DateTimeFormatter.ofPattern("hh:mm:ss a z")
.withZone(ZoneOffset.UTC)));
With that, you get the time converted to:
03:59:22 AM Z

The LocalDateTime class does not support time zones; you can use ZonedDateTime instead.
ZonedDateTime now = ZonedDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm:ss a z");
System.out.println(now.format(formatter));
This no longer throws an exception and prints 06:08:20 PM EDT for me, but the timezone will differ depending on your location.

Related

Convert input second into Month

Months are represented by numbers ranging from 0 to 11. For example, 0 is January, 1 is February, etc.
The code would be
double mon = (sec/2592000);
But how do I control the range from 0-11?
You can use mod operation to control the range:
double mon = ((sec/2592000 - 1) % 12) // from 0 to 11

LocalDateTime as total nanoseconds

I'm working with LocalDateTime objects and would like to store these as Long with nano second precision.
I've tried converting between Instant representation but so far failing.
For example:
localDateTime.toInstant(ZoneOffset.UTC).getNano
Returns only the nano seconds segment of localDateTime - is there a way to return the complete value in nanoseconds?
Similar to toEpochSecond but rather than in seconds, nanoseconds?
2262-04-11T23:47:16.854775807Z = Long.MAX_VALUE of nanos
Building on the correct Answers by Jean-Baptiste Yunès and by assylias explaining that a 64-bit long integer cannot represent all Instant values as a count of nanoseconds since 1970-01-01T00:00Z…
You could use a long/Long for a count of nanoseconds to represent moments for the next two centuries, up to 2262-04-11T23:47:16.854775807Z, if my math is correct:
Instant.ofEpochSecond( ( Long.MAX_VALUE / 1_000_000_000L ) , ( Long.MAX_VALUE % 1_000_000_000L ) )
FYI, Long.MAX_VALUE = 9223372036854775807.
I'm not saying it is a good idea to do so. I am simply showing the possibility to demonstrate the issues at hand.
See code run live at IdeOne.com.
long seconds = ( Long.MAX_VALUE / 1_000_000_000L ) ;
long fraction = ( Long.MAX_VALUE % 1_000_000_000L ) ;
long total = ( ( seconds * 1_000_000_000L ) + fraction ) ;
Instant instant = Instant.ofEpochSecond( seconds , fraction ) ;
System.out.println( "Long.MAX_VALUE: " + Long.MAX_VALUE ) ;
System.out.println( "seconds: " + seconds ) ;
System.out.println( "fraction: " + fraction ) ;
System.out.println( "total: " + total ) ;
System.out.println( "instant: " + instant ) ;
Long.MAX_VALUE: 9223372036854775807
seconds: 9223372036
fraction: 854775807
total: 9223372036854775807
instant: 2262-04-11T23:47:16.854775807Z
There is no such method because you can't store all instants in a long number of nanoseconds.
If you are happy that the range of dates you are interested in can all fit in a long as a number of nanoseconds since the epoch, you can calculate it yourself with:
long nanos = ( instant.getEpochSecond * 1_000_000_000L ) + instant.getNano
Note that this will overflow if the date is too far in the past or the future.
From java API documentation:
The range of an instant requires the storage of a number larger than a
long. To achieve this, the class stores a long representing
epoch-seconds and an int representing nanosecond-of-second, which will
always be between 0 and 999,999,999.
Then getting total of nanos from Instant can't be retrieved in a single primitive type as long.
The correct way to get the total number of nanoseconds since EPOCH from a LocalDateTime object is:
Create an Instant object from your LocalDateTime object
Sum up the result of these 2 methods:
getEpochSecond() - documentation
Gets the number of seconds from the Java epoch of 1970-01-01T00:00:00Z.
getNano() - documentation
Gets the number of nanoseconds, later along the time-line, from the start of the second.
Sample Code
public static void main(String args[]) {
Instant instant = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant();
long epochNanos = TimeUnit.NANOSECONDS.convert(instant.getEpochSecond(), TimeUnit.SECONDS);
epochNanos += instant.getNano();
System.out.print("Total nanos since EPOCH: " + epochNanos);
}

Joda time PeriodFormatterBuilder, can I omit weeks and use only days?

I have seen this, but is it possible to use only month and days, not weeks?
For example, instead of "1 month 2 weeks 2 days", I want "1 month 16 days".
You can use a solution similar to the answer you linked, but you'll also need to use a org.joda.time.PeriodType to normalized the period:
// 1 month, 2 weeks and 2 days
Period p = new Period(0, 1, 2, 2, 0, 0, 0, 0);
PeriodFormatter fmt = new PeriodFormatterBuilder()
// months
.appendMonths().appendSuffix(" month", " months").appendSeparator(" and ")
// days
.appendDays().appendSuffix(" day", " days")
.toFormatter();
System.out.println(fmt.print(p.normalizedStandard(PeriodType.yearMonthDayTime())));
This will print:
1 month and 16 days

Java date class interesting

End date was being computed to be earlier than the start date
Date startDate = new Date();
Date endDate = new Date(startDate.getTime() + (24 * 3600000 * 42));
System.out.println(startDate);
System.out.println(endDate);
output :
Tue Sep 17 01:46:31 EEST 2013
Mon Sep 09 08:43:43 EEST 2013
why the output is not correct ?
Your integer arithmetic has overflowed. The maximum possible value of an int is 2147483647 or Integer.MAX_VALUE (a little over 2 billion), but multiplying your integer literals would yield 3628800000 (about 3.6 billion). The result is a negative number (-666167296), and an earlier date.
Try casting one of your literals as a long to force long arithmetic (or use long literals):
( (long) 24 * 3600000 * 42)
or
(24L * 3600000 * 42)
This operation is well within the range of long values (max value 9223372036854775807, over 9 quintillion).
24 * 3600000 * 42 is 3,628,800,000 which does not fit into an int. Rollover occurs. Force the use of a long by casting one of the factors:
24L * 3600000 * 42
The number you're trying to add is 24 * 3600000 * 42 which is equal to 3,628,800,000. This is larger than 2,147,483,647 which is the maximum value that can be represented with the given data type. What you're experiencing is an overflow, meaning that after crossing the maximum value, the number loops back to its lowest value, which is in the negative. Therefore, you're adding a negative value to the date.

Parsing a String to a Date [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I have a String 2012-10-23 which I need to convert into a Date object.
Can I pass this string directly to the below function
Date date = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH).parse(string);
Date date = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse(string);
for 2012-10-23 your format should be "yyyy-MM-dd"
String string = "2012-10-23";
Date date = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse(string);
Letter Date or Time Component Presentation Examples
G Era designator Text AD
y Year Year 1996; 96
Y Week year Year 2009; 09
M Month in year Month July; Jul; 07
w Week in year Number 27
W Week in month Number 2
D Day in year Number 189
d Day in month Number 10
F Day of week in month Number 2
E Day name in week Text Tuesday; Tue
u Day number of week (1 = Monday, ..., 7 = Sunday) Number 1
a Am/pm marker Text PM
H Hour in day (0-23) Number 0
k Hour in day (1-24) Number 24
K Hour in am/pm (0-11) Number 0
h Hour in am/pm (1-12) Number 12
m Minute in hour Number 30
s Second in minute Number 55
S Millisecond Number 978
z Time zone General time zone Pacific Standard Time; PST; GMT-08:00
Z Time zone RFC 822 time zone -0800
X Time zone ISO 8601 time zone -08; -0800; -08:00
No you can't, this is how
String string = "2012-10-23";
Date date = new SimpleDateFormat("yyyy-MM-dd").parse(string);

Categories