How to remove the SECONDS field from a DateFormat - java

I want to print a time without seconds in the default format for the locale.
So I get the formatter with getTimeInstance() or getTimeInstance(int style). But even when I use a SHORT style it will contain the seconds part of the time as well.
Is there any way (apart from creating my own format, which then would not be the locale default and manually maintained) I can grab the default and split off the seconds ?
Thanks
Roman

DateFormat.getTimeInstance(DateFormat.SHORT) works perfectly fine here: from 20:00:00 to 20:00 and from 8:00:00 PM to 8:00 PM.

EDIT: This is insufficient (as stated by the first comment below). I'm keeping this here for the sake of history and to keep others from responding in a similar fashion :)
Have you considered saving the current format as a string and manually removing the seconds using String's substring method?

In case someone is reading this and either uses Java 8 or later or is fine with a (good and futureproof) external library:
DateTimeFormatter noSeconds = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
.withLocale(Locale.ITALY);
LocalTime time = LocalTime.now(ZoneId.systemDefault());
System.out.println(time.format(noSeconds));
This just printed:
15.26
Please substitute your desired locale instead of Locale.ITALY. Use Locale.getDefault() for your JVM’s locale setting. I believe it prints without seconds in all locales.
In the code I have used a LocalTime object, but the same code works for many other date and time classes including LocalDateTime, OffsetDateTime, OffsetTime and ZonedDateTime.
To use DateTimeFormatter and any of the other classes mentioned on Android you need the ThreeTenABP. More details on how to in this question: How to use ThreeTenABP in Android Project. For any non-Android Java 6 or 7, use ThreeTen Backport.

Related

Getting the UTC timestamp in Java

An old Stack Overflow posting suggests that the way to get the UTC timestamp in Java is the following:
Instant.now() // Capture the current moment in UTC.
Unfortunately this does not work for me. I have a very simple program (reproduced below) which demonstrates different behavior.
On Windows: the time is the local time and it is labeled with the offset with GMT
On Linux: the time is again the local time, and it is labeled correctly for the local timezone
Question: How do we display the UTC timestamp in a Java program?
My sample source code is as follows:
import java.time.Instant;
import java.util.Date;
public class UTCTimeDisplayer {
public static void main(String[] args) {
System.out.println(System.getProperty("os.name"));
Date currentUtcTime = Date.from(Instant.now());
System.out.println("Current UTC time is " + currentUtcTime);
}
}
Windows Output:
C:\tmp>java UTCTimeDisplayer
Windows 10
Current UTC time is Fri Jan 22 14:28:59 GMT-06:00 2021
Linux Output:
/tmp> java UTCTimeDisplayer
Linux
Current UTC time is Fri Jan 22 14:31:10 MST 2021
Your code:
Date.from(Instant.now())
You are mixing the terrible legacy classes with their replacement, the modern java.time classes.
Don’t.
Never use Date. Certainly no need to mix with java.time.Instant.
To explain your particular example, understand that among the Date class’ many poor design choices is the anti-feature of its Date#toString method implicitly applying the JVM’s current default time zone while generating its text.
You ran your code on two different JVMs that had different current default time zones. So you got different outputs.
Sun, Oracle, and the JCP gave up on the legacy date-time classes. So should we all. I recommend you not spend time trying understand Date, Calendar, SimpleDateFormat, and such.
You asked:
Question: How do we display the UTC timestamp in a Java program?
Instant.now().toString()
See that code run live at IdeOne.com.
2021-01-22T21:50:18.887335Z
You said:
On Windows: …
On Linux: …
You’ll get the same consistent results from Instant.now().toString() across Windows, Linux, BSD, macOS, iOS, Android, AIX, and so on.
Here is a table I made to guide you in transitioning from the legacy classes.
The java.util.Date object is not a real date-time object like the modern date-time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). When you print an object of java.util.Date, its toString method returns the date-time in the JVM's timezone, calculated from this milliseconds value. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFormat and obtain the formatted string from it.
I would suggest you simply use Instant.now() which you can convert to other java.time type.
The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
However, if you still want to use java.util.Date, use SimpleDateFormat as mentioned above.
Demo:
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
Date currentUtcTime = Date.from(Instant.now());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println("Current UTC time is " + sdf.format(currentUtcTime));
}
}
Output:
Current UTC time is 2021-01-22 21:53:07 UTC
suggests that the way to get the UTC timestamp in Java is the following:
Instant.now() // Capture the current moment in UTC.
This, and most answers in this thread, are misleading.
Instant represents an instant in time. It's 'solarflares' time: Absolutely not one iota about it represents anything that is invented by human brains, and UTC is a timezone: A human invention. The cosmos, the sun, astronomy - they have no idea what UTC is, and don't care - and that's what Instant is all about. Instants are devoid of such human concepts as 'hours' or 'days' or 'timezones'. It makes no sense to ask an instant what day it happened on. It cannot tell you; some event occurred: If I ask a russian from the 19th century when that happened, they'll likely give a completely different answer vs. if I ask someone living a mere 100 miles west, for example. Instant doesn't know which localization to apply and thus doesn't let you ask it this question - that's a good thing, objects should not expose methods to which any answer it gives is either gobbledygook or at least requires knowing about all sorts of surprising caveats.
Crucially, if you tell me '... in UTC', you surely can tell with exacting detail which month, which day, etcetera. And Instant does not do this, which is why it is misleading to say that a java.time.Instant represents a moment of time in UTC. It doesn't. It represents a moment in time (not in any particular timezone).
Yeah, internally Instant, just like Date, is just a light wrapper around what System.currentTimeMillis() returns: "millis since epoch", but the crucial thing to understand about it, is that 'UTC' is not part of what it means, and therefore, when you give an Instant instance to some other method (such as System.out.println, to a database via JDBC, etc), that method is under absolutely no obligation to assume that UTC is semantically relevant.
When you want to mix human notions of time keeping (years, days, months, hours, minutes, milliseconds, and, yeah, timezones) with the notion of a more or less absolute* time, the right answer is java.time.ZonedDateTime. Note that any representation of time in something that isn't java.time.* based is by definition broken, as it is in most programming languages - turns out time is a lot more complex than most takes on a library to represent it realize. The fact that java.time is in effect the 4th attempt at writing a time library should be ample indication that it's hard to get it right.
ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC);
THAT is what you want - that isn't just implementation-detail-wise what you want, but it is code that exactly describes what you mean: Right now, at the UTC time zone, stored in an object that semantically doesn't just store the right time but also stores, and tightly entangles into its very identity, that it is specifically in UTC and is not to be re-interpreted, moved to the local zone, or any other such shenanigans - at least, not unless you explicitly ask it to do so.
Date currentUtcTime = Date.from(Instant.now());
Note that Date is the old API and therefore necessarily broken. In this case, Date is a lying liar who lies - it doesn't represent a date, it represents an instant; it is badly named. (The second API is Calendar, also broken. For example, that is also a lying liar who lies: It doesn't represent a Calendar whatsoever. It represents some bizarre amalgamation of a zoned datetime and an instant and is fit to represent neither as a consequence). Any time you go to the Date API weirdness ensues, and something as simple as 'I just want the concept of the time, at some specific moment, in UTC' isn't possible in these APIs. You are now dependent on barely defined behaviour of all the various libraries up and down the chain - you're effectively stuck praying that they do the right thing, or delving into exotic settings to try to cajole these libraries into doing what you want.
TL;DR: Use java.time.
*) Note that ZonedDateTime is not absolute. For example, if you have the time January 20th, 2023, 8 in the morning, at Europe/Amsterdam, in the form of a ZonedDateTime object, then the amount of seconds that will pass between now and that moment sure seems like it does not change and will not change when e.g. amsterdam goes through an hour change due daylight savings. However, if the dutch government decrees that henceforth The Netherlands will no longer move the clocks at all and will stay in summer time forever (which is likely - EU directive is already in place, it's now just a matter of when), then at the moment the gavel lands, your appointment shifts by 1 hour exactly.
That hopefully provides crucial insight in the difference: Instant, representing events (hence why I like to call it 'solarflares time', to disentangle it from human time keeping concepts as much as possible), doesn't even understand the very concept of such a decision having an effect on things. ZonedDateTime on the other hand is inherently bound up in it - hence the Zone in ZonedDateTime.
If you want to store barber appointments and use Instant to do it, you WILL be an hour late or early sooner rather than later.
An Instant object and also a Date object by themselves
only contain a point in time, but no timezone information.
Furthermore, the toString() method of the Date class
implicitly chooses the timezone provided by the system environment,
which is not what you want.
Therefore you need to chose the timezone (in your case UTC) explicitly.
For example like this:
Instant instant = Instant.now();
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.UTC);
System.out.println("Current UTC time is " + offsetDateTime);
This will (independently from the operation system) print
Current UTC time is 2021-01-22T22:37:21.950354100Z
where the trailing Z denotes the zero timezone offset (i.e. UTC).
A simple method that could work!
My requirement was date time with milliseconds
2021-11-25 19:55:00.743
private String getUTCTimestamp() {
ZonedDateTime utc = ZonedDateTime.now(ZoneOffset.UTC);
return utc.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));
}
Instant.now() is essentially the period of time since the epoch, (midnight 1 January 1970 in UTC), but you are using a Date to present that instant. Date is a reflection of the instant with millisecond precision, but as explained in the documentation at https://docs.oracle.com/javase/8/docs/api/java/util/Date.html, presenting a date should be done using a Calendar, as the presentation of a Date depends on the host. Essentially Date wraps the instant but is displayed according to other factors.
The simplest approach now if you want to output the instant is to use OffsetDateTime so that you can elect to present the instant in your desired timezone - UTC in your case. Use either OffsetDateTime.now() or OffsetDateTime.ofInstant() but if you are using the instant within your application logic then just stick with Instant.
Sometimes your program has to work with older java versions, so here is an example for 1.5:
java.text.SimpleDateFormat tfGMT = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
java.util.Calendar cUTC = java.util.Calendar.getInstance (java.util.TimeZone.getTimeZone ("GMT+0"));
tfGMT.setCalendar (cUTC);
java.util.Date d= new java.util.Date ();
String s= tfGMT.format (d);
System.out.printf ("now=%s [unix ts=%d.%03d]\n", s, d.getTime()/1000, d.getTime()%1000);
Mind you, the first three lines don't have to be repeat at every call, but keep in mind that SimpleDateFormat is not thread-safe. (Simple solution: create one for each thread.)
Example usage (it shows that setting TZ doesn't affect UTC-timestamp):
$ TZ=GMT+3 java5 now_utc; TZ=GMT-3 java5 now_utc
now=2021-01-24 12:56:14 [unix ts=1611492974.264]
now=2021-01-24 12:56:14 [unix ts=1611492974.726]

Why Calendar.SEPTEMBER is not working? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I want to see a month which contains whole days.
private void createRandomData(InMemoryCursor cursor) {
List<Object[]> data = new ArrayList<>();
Calendar today = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault());
today.set(Calendar.HOUR_OF_DAY,0);
today.set(Calendar.MINUTE, 0);
today.set(Calendar.SECOND, 0);
today.set(Calendar.MILLISECOND, 0);
mStart = (Calendar) today.clone();
mStart.add(Calendar.SEPTEMBER, -5);
while (mStart.compareTo(today) <= 0) {
data.add(createItem(mStart.getTimeInMillis()));
mStart.add(Calendar.SEPTEMBER, 1);
}
cursor.addAll(data);
}
When I write Calendar.SEPTEMBER(or other months), I see red line on Calendar.SEPTEMBER which contains:
Must be one of: Calendar.ERA, Calendar.YEAR, Calendar.MONTH, Calendar.WEEK_OF_YEAR, Calendar.WEEK_OF_MONTH, Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH, Calendar.AM_PM, Calendar.HOUR, Calendar.HOUR_OF_DAY, Calendar.MINUTE, Calendar.SECOND, Calendar.MILLISECOND, Calendar.ZONE_OFFSET, Calendar.DST_OFFSET less... (Ctrl+F1)
This inspection looks at Android API calls that have been annotated with various support annotations (such as RequiresPermission or UiThread) and flags any calls that are not using the API correctly as specified by the annotations. Examples of errors flagged by this inspection:
Passing the wrong type of resource integer (such as R.string) to an API that expects a different type (such as R.dimen).
Forgetting to invoke the overridden method (via super) in methods that require it
Calling a method that requires a permission without having declared that permission in the manifest
Passing a resource color reference to a method which expects an RGB integer value.
...and many more. For more information, see the documentation at developer.android.com/tools/debugging/annotations.html
When I run it despite the red line, It shows complicated dates like:
see
I use this library from GitHub:https://github.com/jruesga/timeline-chart-view
Is problem related to library? or It is about Java calendar?
As explained in #Michael's answer, you can't use Calendar.SEPTEMBER in the add method.
If you want to add or subtract a specified number of months, just use Calendar.MONTH. If you want to add/subtract days, you use Calendar.DAY_OF_MONTH and so on.
The Calendar API might be confusing sometimes (most times, IMO), and has lots of problems and design issues.
In Android, there's a better alternative: you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. To make it work, you'll also need the ThreeTenABP (more on how to use it here).
As you're getting a Calendar in the default timezone, a good candidate for replacement is a org.threeten.bp.ZonedDateTime (it represents a date and time in a specific timezone). First I use the now() method (that takes the current date/time at the JVM default timezone). Then I use a org.threeten.bp.LocalTime to set the time to midnight.
I also use the minusMonths method to get a date 5 months before the current date, and inside the loop I use the toInstant() method, to get the millis value, and the plusMonths method to get the next month:
// get today at default timezone, at midnight
ZonedDateTime today = ZonedDateTime.now().with(LocalTime.MIDNIGHT);
// 5 months ago
ZonedDateTime start = today.minusMonths(5);
while (start.compareTo(today) <= 0) {
data.add(createItem(start.toInstant().toEpochMilli()));
start = start.plusMonths(1);
}
If you want to add/subtract minutes instead of months, for example, you can use the methods minusMinutes and plusMinutes. There are other methods for another units as well (such as hours, days, and so on), check the javadoc to see all the options.
The problem of using the default timezone is that it can be changed without notice, even at runtime, so it's better to always make it explicit which one you're using.
With Calendar, you can use TimeZone.getTimeZone(zoneName):
Calendar todayCal = Calendar.getInstance(TimeZone.getTimeZone("Europe/London"), Locale.getDefault());
And with ThreeTen Backport, you can use ZoneId.of(zoneName):
ZonedDateTime today = ZonedDateTime.now(ZoneId.of("Europe/London")).with(LocalTime.MIDNIGHT);
In the example above, I used Europe/London, but you can change it to any timezone you want. The API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds() or TimeZone.getAvailableIDs().
You are using an incompatible option. The first parameter of Calendar.add() is a Unit of Time (Day, Week, Hour etc) as defined by the possible options outlined in the error. Calendar.SEPTEMBER is not a unit of time, it is a convenience constant representing the MONTH of September that is typically used in the set() method instead.
Assuming you're iterating through months, you'll need Calendar.MONTH instead.

Handling date/time in java/android and daylight savings

I am making a diary application for Android and I want to allow the user to select the timezone they are in. Time has always been a area of confusion for me programatically.
I am going to create an enum for the available timezones.
I am going to save date/time entries to a sqlite in long UTC format, then handling offsets and DST programmatically in Java for display purposes.
I am actually aware of Java's limitations when it comes to date/time handling.
Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC")); //returns the current time in UTC format
Long utcLong = utc.getTimeInMillis(); //returns current utc time in long for database insertion
Question 1: How would I apply an offset to it and account for when to apply any additional DST offsets? Because not all timezones observe DST and DST comes into effect at different dates for different timezones.
Question 2: Java's TimeZone class has something like ~800 ids, it would be annoying to the user to have to scroll through ~800 options to find the one that applys to them. Is there a short list available? I'm thinking there are around ~50 useful timezones.
First of all, I recommend you to not use the Calendar class. It's outdated and has lots of bugs and design issues. This terrible API was replaced by much better ones:
for Java >= 8, use the new date-time API
for Java <= 7, use the ThreeTen Backport
for Android, you can also try ThreeTenABP
The code below works for all, the only difference is the package names (in Java 8 is java.time and in ThreeTen Backport is org.threeten.bp), but the classes and methods names are the same.
To get the UTC current date/time, the best choice is to use Instant class:
// current date/time in UTC - now() always returns the current instant in UTC
Instant instant = Instant.now();
System.out.println(instant); // 2017-06-03T18:03:55.976Z
// equivalent to calendar.getTimeInMillis(), it returns a long
System.out.println(instant.toEpochMilli()); // 1496513035976
To convert this instant to a timezone, you can use the ZoneId with a ZonedDateTime:
// ZoneId accepts the same IDs used by TimeZone
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// convert instant to timezone
ZonedDateTime z = instant.atZone(zone);
System.out.println(z); // 2017-06-03T15:03:55.976-03:00[America/Sao_Paulo]
// converts back to UTC (returns an Instant)
System.out.println(z.toInstant()); // 2017-06-03T18:03:55.976Z
The code above already takes care of DST changes, so the conversion from and to UTC is straightforward.
Timezone list
You say that you have a list of ~50 "useful" timezones. I don't know what criteria you used to define that list, but what happens if an user is in a timezone that's not in the list?
There are some ideas of timezone-picking user interfaces in this link and here. You can choose one and adapt to your app.
I also suggest to not use (if possible) the 3-letter timezone abbreviations (like CST or PST) because they are ambiguous and not standard. It's better to use the full names (like America/Sao_Paulo or Europe/London) as they are the ones used by Java's APIs (you can get the full list with ZoneId.getAvailableZoneIds()) and they are configured with all DST changes for each zone.

SimpleDateFormat issue when parsing a String in ISO 8601 format

Appreciate there are lots of similar posts on this but I couldn't find a specific one to help.
I'm trying to convert this string to a Date in Java
2017-05-16 06:24:36-0700
But it fails each time with this code
Date Login = new SimpleDateFormat("dd/MM/yy HH:mm:ss").parse("2017-05-16 06:24:36-0700");
Now I'm presuming its due to the timezone info at the end - I just can't figure out how to set the format. I tried this but no luck
SimpleDateFormat("dd/MM/yy HH:mm:ssZ")
Any ideas?
The date format passed to your SimpleDateFormat is "dd/MM/yy", while the date you are trying to parse is of the format "yyyy-MM-dd". Try this instead:
Date login = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ").parse("2017-05-16 06:24:36-0700");
As a side note, depending on which version of Java you are using, I would recommend using the new java.time package (JDK 1.8+) or the back port of that package (JDK 1.6+) instead of the outdated (no pun intended) Date and/or Calendar classes.
Instant login = Instant.from(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssZ").parse("2017-05-16 06:24:36-0700"));
I have already upvoted Bryan’s answer exactly because it includes and recommends the java.time solution. I need to add a few thoughts, though.
Your code, reviloSlater, throws away the time zone information (more precsely, zone offset information), I’m not sure I would dare do that from the outset. With java.time classes it’s more natural to include it, and it’s easy to discard at a later point when we are sure we don’t need it.
To parse with offset:
OffsetDateTime loginOdt = OffsetDateTime.parse("2017-05-16 06:24:36-0700",
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssZ"));
To drop the time zone offset information
LocalDateTime loginLdt = loginOdt.toLocalDateTime();
A LocalDateTime is a date and a time without any time zone or offset information. In this case of course we get
2017-05-16T06:24:36
Bryan’s java.time code too uses the time zone offset information from the string. Edit: after Bryan’s edit that code now works and gives us:
2017-05-16T13:24:36Z
This is the same point in time (Instant.toString() prints the time in UTC). Another way is, with the OffsetDateTime from before we can just do
Instant login = loginOdt.toInstant();
java.time is loaded with possibilities.

Midnight date with timezone sent to timezone-ignorant system

Quick summary of my issue first, then details further below.
I have a Calendar date with 00:00:00 as the time as it's not important to the business. This value is sent to a webservice which generates a XML in which the value ends up in the following format : 2014-09-12T07:55:07.000Z. I have noticed that this is the original value converted to a +0 timezone (UTC) (ours is CET, +1, but currently CEST, +2, because of DST).
I currently have no idea whether the system reading the XML takes timezones into account or would extract 2014-09-12 and assume it's in the +2 timezone.
What I've noticed is that sending "2014-09-12 00:00:00" local time (tz +2) ends up as 2014-09-11T22:00:00.000Z in the XML. No big surprise, it converted it... but if it's interpreted as is by the other system, it will think the date is a day earlier than it should be.
What can be done to ensure this gets interpreted as intended?
I was thinking of using noon instead of midnight to make sure timezone shifts wouldn't impact interpretation, but it feels like a dirty trick. Or maybe I should cheat and have the Calendar timezone be +0 so it's not time-shifted when put in the XML?
Q&A
Why do you "send a Calendar to a webservice"?
The application is in Coldfusion 7. To communicate with SOAP webservices, the server generates a set of Java classes that fit the definition of the argument expected by the webservice. The argument is apparently a single big object with a lot of attributes and sub-attributes. So one instantiates the main Java class and uses setters and further instanciations of other classes to "fill out" all the attributes.
Do you have to use Calendar?
Yes, the Java object definition cannot be changed. It expects Calendar for all dates.
What's this 2014-09-11T22:00:00.000Z format?
I have no idea. This seems to be what the end system expects for dates.
You should use JODA
Unless JODA classes extend Calendar and are compatible with Java 1.3 (current Java version on the Coldfusion server -- yes it's old), I doubt it will work.
How much can you do on the other system?
The other system is the responsibility of a different team and is apparently very hard to change. I expect the solution will have to be found on the side of our application.
Although the time value in your Calendar object is not important to your business, it is important to the webservice that you use and have no control over. The calendar object specifies an instant in time, so you must make sure that instant is in the day that is important to you. I recommend you use midday, as you suggested already. I also recommend that you create your Calendar object in the UTC timezone:
Calendar myCalendar=Calendar.getInstance(TimeZone.getTimeZone("UTC"));

Categories