Going on a Date with Java

Written by Empanado | Published 2017/08/03
Tech Story Tags: programming | java | software-development | date-with-java | java8

TLDRvia the TL;DR App

Photo by Heather Zabriskie on Unsplash

Java 8 has all its streams in all the right places, just my cup of coffee. You know what, I think I’ll take it out for a digital date. It’s Friday the 4th of August, just after 15:00 CEST.

How late will we meet?

No worries, I’ll figure it out. Let me just see which classes to use.

Date

That’s a good name! Let’s have a look.

The class Date represents a specific instant in time, with millisecond precision.

Yeah I need to be precise. Let’s go with this one.

>>> Date date = new Date();

Look at all those dates, three in one line, this will be great.

>>> System.out.println(date);Fri Aug 04 15:10:50 CEST 2017

Hey, a timezone. Where did that come from?

public String toString()Converts this Date object to a String of the form:dow mon dd hh:mm:ss zzz yyyywhere:<snip>zzz is the time zone (and may reflect daylight saving time). Standard time zone abbreviations include those recognized by the method parse. If time zone information is not available, then zzz is empty - that is, it consists of no characters at all.

Ok, so that’s not an answer. Stackoverflow, you’re our only hope.

What time zone does Date.toString() display? - Stack Overflowhttps://stackoverflow.com/questions/4199217/what-time-zone-does-date-tostring-displayIt displays using TimeZone.**_getDefault_**() which, in turn, will default to the time zone of the operating system it is running on (i.e. the host)

Ah, so the conversion is just for display then?

>>> System.out.println(date.getHours());15

What?

Let’s have a look at the docs.

@Deprecatedpublic int getHours()

Deprecated. As of JDK version 1.1, replaced by Calendar.get(Calendar.HOUR_OF_DAY).

Oh, of course. No worries, I’ll go check out this Calendar.

Calendar

Calendar cal = Calendar.getInstance();

Of course, instantiation is so last decade. Singletons is where it’s at! I’m sure they took thread safety into account though. Let’s ask Stack Overflow to be sure.

Is java.util.Calendar thread safe or not? - Stack Overflowhttps://stackoverflow.com/questions/12131324/is-java-util-calendar-thread-safe-or-notAug 26, 2012 - If you read the code you will see that none of the instance methods are synchronized, and none of the instance fields are volatile . ... In short, the Calendar class is not thread-safe, and GregorianCalendar isn't either because it inherits the non-thread-safe fields and methods.

Oh. Well. Nevermind, it’s not that important for me anyway. Let’s go see what we can do!

Getting and Setting Calendar Field ValuesThe calendar field values can be set by calling the set methods.

Sure, the set methods. Like setHours and setMonth, right?

public void set(int field, int value)Sets the given calendar field to the given value.

Ehm, so how do you use this?

cal.set(Calendar.MINUTE, 20);

Of course, because the biggest advantage of having a type system is so that you can ignore it explicitly. But this is probably just the low level API, I’m sure that this is not all we have.

public abstract void add(int field, int amount)Adds or subtracts the specified amount of time to the given calendar field, based on the calendar's rules.

public abstract void roll(int field, boolean up)Adds or subtracts (up/down) a single unit of time on the given time field without changing larger fields.

public void roll(int field, int amount)Adds the specified (signed) amount to the specified calendar field without changing larger fields. A negative amount means to roll down.

What kind of an API is this? What are you talking about? Why are you rolling with dates, and what the hell does it mean to “roll down”? Does this class only make sense if you’re on a hill?

Are we regularly checking up on the person who designed this thing? Because I’m not sure if he’s going to be OK.

How come there are no operations for things that I actually want to do, on a level that is relevant to me? Why can’t I go to next week, or to the start or end of the day? Why do you expect me to implement all this functionality by myself every time I work with you?

Java, you’re giving me second thoughts.

The designers of Java’s date/time libraries.

Java 8

I’m obviously behind the times though. Java 8 is where it’s at, with its all-new date/time API. What do we get?

The first classes you will probably encounter when using the new API are LocalDate and LocalTime.

Alright, let’s have a look.

class **LocalDateTime**A date-time without a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30.

Ok, no time-zone. So that means I must provide it when I want to view the date?

>>> LocalDateTime timePoint = LocalDateTime.now();>>> System.out.println(timePoint);2017-08-04T15:23:41.541

Hey, that’s in my timezone. But it didn’t have timezone information.

public static LocalDateTime now()Obtains the current date-time from the system clock in the default time-zone.

So you are saying…

>>> System.out.println(timePoint.getHour());15

Let’s see what the docs have to say about this.

This class does not store or represent a time-zone. Instead, it is a description of the date, as used for birthdays, combined with the local time as seen on a wall clock. It cannot represent an instant on the time-line without additional information such as an offset or time-zone.

So it’s a fancy string? I mean, a time makes no sense without a timezone. You always have a timezone, even if you pretend you don’t, we’ve just seen it happen. Why not always force the user to be explicit? When is using the default time zone ever better? And why add some concept of “local” and wall clocks and hide away things that are really not that difficult?

Isn’t there something simple and straightforward that I can use?

Class InstantAn instantaneous point on the time-line.

This class models a single instantaneous point on the time-line. This might be used to record event time-stamps in the application.

I’m cautiously optimistic…

>>> Instant instant = Instant.now();>>> System.out.println(instant);2017-08-04T15:28:01.354Z

UTC by default, that makes sense to me. This is promising! Just a simple, predictable value on the timeline, always using UTC, so I can simply convert when I need to display it it to the user. And I’m sure they’ve at least implemented a better API than the Calendar…

public int get(TemporalField field)Gets the value of the specified field from this instant as an int.

public Instant plus(long amountToAdd, TemporalUnit unit)Returns a copy of this instant with the specified amount added.

You know what Java, I think I’ll stay home and play with my Python.

It’s not all bad

Let’s take a step back, because the API of LocalDateTime is actually quite nice.

public static LocalDateTime of(int year,int month,int dayOfMonth,int hour,int minute,int second,int nanoOfSecond)Obtains an instance of LocalDateTime from year, month, day, hour, minute, second and nanosecond.

public LocalDateTime plusWeeks(long weeks)Returns a copy of this LocalDateTime with the specified number of weeks added.

This method adds the specified amount in weeks to the days field incrementing the month and year fields as necessary to ensure the result remains valid. The result is only invalid if the maximum/minimum year is exceeded.

public LocalDateTime withHour(int hour)Returns a copy of this LocalDateTime with the hour-of-day altered.

And there is a class that makes time zones much more explicit that implements the same API.

ZonedDateTime is a date and time with a fully qualified time zone. This can resolve an offset at any point in time.

class **ZonedDateTime**A date-time with a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00 Europe/Paris.

Let’s try it out!

>>> ZonedDateTime timePoint = ZonedDateTime.now();>>> System.out.println(timePoint);2017-08-04T15:33:02.325+02:00[Europe/Amsterdam]>>> System.out.println(_timePoint._getHour());15>>> timePoint = timePoint.of(1983, JULY.getValue(), 20, 15, 27, 40, 0, ZoneId.of("Europe/London"));>>> System.out.println(timePoint);1983-07-20T15:27:40+01:00[Europe/London]>>> _timePoint = timePoint._plusYears(30).minusHours(4)>>> System.out.println(timePoint);2013-07-20T11:27:40+01:00[Europe/London]

This is explicit, functional and quite elegant. The API is fluent, which makes setting specific dates or performing multiple modifications a much more civil affair. And there are no surprises in there either.

Strangely, the earlier discussed classes are usually described before arriving at this one, and a lot of focus goes towards the LocalX classes. But I would suggest just using ZonedDateTime for most situations. In general, when dealing with dates and times, it’s best practice to internally treat everything as UTC explicitly. You then convert the datetime to the applicable timezone, which can be user specific, only at the point in your application where you have to display it. ZonedDateTime can facilitate this pattern just fine.

The contents of this post is largely an attempt at satire and is not an accurate reflection of the thought processes or programming abilities of the author. In reality, more swearing was involved.


Published by HackerNoon on 2017/08/03