JavaRush/Java Blog/Random EN/How not to get lost in time - DateTime and Calendar

How not to get lost in time - DateTime and Calendar

Published in the Random EN group
members
Hello! Today we will start working with a new data type that we have not encountered before, namely dates. How not to get lost in time - DateTime and Calendar - 1I think there is no need to explain what a date is :) In principle, it is quite possible to write the current date and time in Java in a regular string.
public class Main {
   public static void main(String[] args) {

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
But this approach has many disadvantages. The class Stringwas created to work with text, and it has appropriate methods. If we need to somehow manage the date (add 2 hours to it, for example), it Stringwon’t work here. Or, for example, display the current date and time at the time the program was compiled into the console. It won’t help here Stringeither: while you write the code and run it, the time will change and the irrelevant will be displayed in the console. Therefore, in Java, its creators provided several classes for working with dates and times. The first one is classjava.util.Date

Java Date Class

We gave it its full name because there is also a class in another package in Java java.sql.Date. Don't get confused! The first thing you need to know about it is that it stores the date in milliseconds that have passed since January 1, 1970. There is even a separate name for this date - “Unix time”. Quite an interesting way, don’t you agree? :) The second thing to remember: if you create an object Datewith an empty constructor, the result will be the current date and time at the time the object was created . StringDo you remember how we wrote that such a task would be problematic for a date format ? The class Datesolves it easily.
public class Main {
   public static void main(String[] args) {

       Date date = new Date();
       System.out.println(date);
   }
}
Run this code several times and you will see how the time will change each time :) This is possible precisely because it is stored in milliseconds: they are the smallest unit of time, which is why the results are so accurate. There is another constructor for Date: you can specify the exact number of milliseconds that have passed from 00:00 January 1, 1970 to the required date, and it will be created:
public class Main {
   public static void main(String[] args) {

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
Console output:

Fri May 30 08:20:12 MSD 2008
We got it on May 30, 2008. “Fri” means the day of the week - “Friday” (Friday), and MSD - “Moscow Daylight Saving” (Moscow summer time). Milliseconds are transmitted in the format long, since their number most often does not fit into int. So, what kind of date operations might we need in our work? Well, the most obvious thing, of course, is comparison . Determine whether one date was later or earlier than another. This can be done in different ways. For example, you can call the . method Date.getTime(), which will return the number of milliseconds that have passed since midnight on January 1, 1970. Let's just call it on two Date objects and compare them with each other:
public class Main {
   public static void main(String[] args) {

       Date date1 = new Date();

       Date date2 = new Date();

       System.out.println((date1.getTime() > date2.getTime())?
               "date1 is later than date2" : "date1 is earlier than date2");
   }
}
Conclusion:

date1 раньше date2
But there is a more convenient way, namely, to use special methods of the class Date: before(), after()and equals(). They all return the result in boolean. The method before()checks whether our date is earlier than the one we pass as an argument:
public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

       Thread.sleep(2000);//pause the program for 2 seconds
       Date date2 = new Date();

       System.out.println(date1.before(date2));
   }
}
Console output:

true
The method works in a similar way after(); it checks whether our date was later than the one we pass as an argument:
public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

       Thread.sleep(2000);//pause the program for 2 seconds
       Date date2 = new Date();

       System.out.println(date1.after(date2));
   }
}
Console output:

false
In our examples, we put the program to sleep for 2 seconds so that the two dates are guaranteed to be different. On fast computers, the time between creating date1and date2can be less than one millisecond, in which case both and before()and after()will return false. But the method equals()in such a situation will return true! After all, it compares exactly the number of milliseconds that have passed since 00:00 January 1, 1970 for each date. Objects will only be considered equal if they match down to the millisecond:
public static void main(String[] args) {

   Date date1 = new Date();
   Date date2 = new Date();

   System.out.println(date1.getTime());
   System.out.println(date2.getTime());

   System.out.println(date1.equals(date2));
}
Here's something else you need to pay attention to. If you open the documentation for the class Dateon the Oracle website, you will see that many of its methods and constructors have been designated as Deprecated(“deprecated”). Here, look: Class Date Here's what the creators of Java themselves say about those parts of classes that have become deprecated: “A program element annotated with @Deprecated is something that programmers are discouraged from using, usually because it is dangerous, or because that there is a better alternative.” This does not mean that these methods cannot be used at all. Moreover, if you yourself try to run the code using them in IDEA, it will most likely work. Let's take for example the deprecated method Date.getHours(), which returns the number of hours from the object Date.
public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());

}
If at the time you run the code, for example, the time is 14:21, it will display the number 14. As you can see, the deprecated method is crossed out, but it works quite well. These methods were not removed completely, so as not to break a bunch of code already written using them. That is, these methods are not “broken” or “removed”, they are simply not recommended for use due to the availability of a more convenient alternative. By the way, it is written about it right in the documentation: How not to get lost in time - DateTime and Calendar - 2Most of the methods of the Date class have been moved to its improved, extended version - the class Calendar. We'll get to know him further :)

Java Calendar

Java 1.1 introduced a new class - Calendar. He made working with dates in Java a little easier than it looked before. The only implementation of the class Calendarwith which we will work is the class GregorianCalendar(it implements the Gregorian calendar, according to which most countries of the world live). Its main convenience is that it can work with dates in a more convenient format. For example, he can:
  • Add a month or day to the current date
  • Check if the year is a leap year;
  • Get individual date components (for example, get the month number from a whole date)
  • And also, a very convenient system of constants has been developed inside it (we will see many of them below).
Another important difference of the class Calendaris that it implements a constant Calendar.Era: you can set the date to the era BC (“Before Christ” - before the birth of Christ, i.e. “before our era”) or AC (“After Christ” - “ our era"). Let's look at all this with examples. Let's create a calendar with the date January 25, 2017:
public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
Months in the class Calendar(as in Date, by the way) start from zero, so we passed the number 0 as the second argument. The main thing when working with a class Calendaris to understand that this is a calendar , and not a separate date. How not to get lost in time - DateTime and Calendar - 3A date is simply a series of numbers representing a specific period of time. And a calendar is a whole device with which you can do a lot of things with dates :) This can be seen quite clearly if you try to output the Calendar object to the console: Output:

java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=10800000,dstSavings=0,useDaylight=false,transitions=79,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=1,ERA=?,YEAR=2017,MONTH=0,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=25,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]
See how much information there is! The calendar has a bunch of properties that a regular date does not have, and all of them are output to the console (this is how the method toString()in the class works Calendar). If, when working, you just need to get a simple date from the calendar, i.e. object Date- this is done using a method Calendar.getTime()(the name is not the most logical, but nothing can be done):
public static void main(String[] args) {

   Calendar calendar = new GregorianCalendar(2017, 0 , 25);
   Date date = calendar.getTime();
   System.out.println(date);
}
Conclusion:

Wed Jan 25 00:00:00 MSK 2017
Now we have “simplified” the calendar to a regular date. Let's move on. In addition to numerical symbols for months, Calendarconstants can be used in the classroom. Constants are static fields of a class Calendarwith an already set value that cannot be changed. This option is actually better, since it improves the readability of the code.
public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
Calendar.JANUARY— one of the constants for indicating the month. With this naming option, no one will forget, for example, that the number “3” means April, and not the third month we are used to - March. You just write Calendar.APRIL- and that's it :) All calendar fields (day, month, minutes, seconds, etc.) can be set individually using the method set(). It is very convenient, since Calendareach field has its own constant in the class, and the final code will look as simple as possible. For example, in the previous example, we created a date, but did not set the current time for it. Let's set the time to 19:42:12
public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar();
   calendar.set(Calendar.YEAR, 2017);
   calendar.set(Calendar.MONTH, 0);
   calendar.set(Calendar.DAY_OF_MONTH, 25);
   calendar.set(Calendar.HOUR_OF_DAY, 19);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   System.out.println(calendar.getTime());
}
Conclusion:

Wed Jan 25 19:42:12 MSK 2017
We call the method set(), pass a constant to it (depending on the field we want to change) and a new value for this field. It turns out that the method set()is a kind of “super-setter” that can set a value not for one field, but for many fields :) Adding and subtracting values ​​in a class Calendaris carried out using the add(). You need to pass into it the field that you want to change, and the number - exactly how much you want to add/subtract from the current value. For example, let's set the date we created back to 2 months ago:
public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 19);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.add(Calendar.MONTH, -2);//to subtract a value - a negative number must be passed to the method
   System.out.println(calendar.getTime());
}
Conclusion:

Fri Nov 25 19:42:12 MSK 2016
Great! We have set the date back to 2 months ago. As a result, not only the month, but also the year has changed, from 2017 to 2016. Calculation of the current year when moving dates, of course, is performed automatically and does not need to be controlled manually. But if for some purpose you need to disable this behavior, you can do that. A special method roll()can add and subtract values ​​without affecting other values. For example, like this:
public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.roll(Calendar.MONTH, -2);
   System.out.println(calendar.getTime());
}
We did exactly the same as in the previous example - we subtracted 2 months from the current date. But now the code worked differently: the month changed from January to November, but the year remained the same as 2017! Conclusion:

Sat Nov 25 10:42:12 MSK 2017
Further. As we said above, all fields of an object Calendarcan be obtained separately. The method is responsible for this get():
public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   System.out.println("Year: " + calendar.get(Calendar.YEAR));
   System.out.println("Month: " + calendar.get(Calendar.MONTH));
   System.out.println("Number of the week in the month: " + calendar.get(Calendar.WEEK_OF_MONTH));// serial number of the week in the month

   System.out.println("Number: " + calendar.get(Calendar.DAY_OF_MONTH));

   System.out.println("Watch: " + calendar.get(Calendar.HOUR));
   System.out.println("Minutes: " + calendar.get(Calendar.MINUTE));
   System.out.println("Seconds: " + calendar.get(Calendar.SECOND));
   System.out.println("Milliseconds: " + calendar.get(Calendar.MILLISECOND));

}
Conclusion:

Год: 2017 
Месяц: 0 
Порядковый номер недели в месяце: 4 
Число: 25 
Часы: 10 
Минуты: 42 
Секунды: 12 
Миллисекунды: 0
That is, in addition to the “super-setter” in the class Calendarthere is also a “super-getter” :) Another interesting point is, of course, working with eras. To create a date “BC” you need to use the field Calendar.Era For example, let’s create a date indicating the Battle of Cannae, in which Hannibal defeated the army of Rome. This happened on August 2, 216 BC. e.:
public static void main(String[] args) {
   GregorianCalendar cannes = new GregorianCalendar(216, Calendar.AUGUST, 2);
   cannes.set(Calendar.ERA, GregorianCalendar.BC);

   DateFormat df = new SimpleDateFormat("dd MMM yyy GG");
   System.out.println(df.format(cannes.getTime()));
}
Here we used the class SimpleDateFormatto display the date in a format that is more understandable to us (the letters “GG” are responsible for displaying the era). Conclusion:

02 авг 216 до н.э.
CalendarThere are many more methods and constants in the class , read about them in the documentation:

Newline to Date

To convert String to Date, you can use the Java helper class - SimpleDateFormat . This is the class you need to convert a date to a format you define. How not to get lost in time - DateTime and Calendar - 5In turn, it is very similar to DateFormat . The only notable difference between the two is that SimpleDateFormat can be used for formatting (converting a date to a string) and parsing the string into a locale-aware date, whereas DateFormat does not support a locale. Additionally, DateFormat is an abstract class that provides basic support for formatting and parsing dates, while SimpleDateFormat is a concrete class that extends the DateFormat class. This is what an example of creating a SimpleDateFormat object and formatting a Date looks like:
SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(1212121212121L);

System.out.println(formatter.format(date));
In the above example we used the pattern "yyyy-MM-dd HH:mm:ss" which means:
  • 4 digits for year (yyyy);
  • 2 digits for month (MM);
  • 2 digits for day (dd);
  • 2 digits for hours in 24-hour format (HH);
  • 2 digits for minutes (mm);
  • 2 digits for seconds (ss).
The separation marks and the order of the pattern symbols are preserved. Console output:
2008-05-30 08:20:12
There are quite a lot of template letters for the SimpleDateFormat class . So that you don't get confused, we have collected them in a table:
Symbol Description Example
G era (in English localization - AD and BC) AD
y year (4-digit number) 2020
yy year (last 2 digits) 20
yyyy year (4-digit number) 2020
M month number (without leading zeros) 8
MM month number (with leading zeros if month number < 10) 04
MMM three-letter month abbreviation (according to localization) Jan
MMMM full month name June
w week of the year (without leading zeros) 4
ww week of the year (with leading zeros) 04
W week in month (without leading zeros) 3
WW week in month (with leading zero) 03
D day of the year 67
d day of the month (without leading zeros) 9
dd day of the month (with leading zeros) 09
F day of the week in the month (without leading zeros) 9
FF day of week in month (with leading zeros) 09
E day of the week (abbreviation) W
EEEE day of the week (full) Friday
u day of week number (without leading zeros) 5
uu number of the day of the week (with leading zeros) 05
a AM/PM marker A.M.
H hours in 24-hour format without leading zeros 6
HH clock in 24-hour format with leading zero 06
k number of hours in 24-hour format 18
K number of hours in 12 hour format 6
h time in 12-hour format without leading zeros 6
hh time in 12-hour format with leading zero 06
m minutes without leading zeros 32
mm minutes with leading zero 32
s seconds without leading zeros eleven
ss seconds with leading zero eleven
S milliseconds 297
z Timezone EET
Z time zone in RFC 822 format 300
Examples of pattern character combinations:
Sample Example
dd-MM-yyyy 01-11-2020
yyyy-MM-dd 2019-10-01
HH:mm:ss.SSS 23:59.59.999
yyyy-MM-dd HH:mm:ss 2018-11-30 03:09:02
yyyy-MM-dd HH:mm:ss.SSS 2016-03-01 01:20:47.999
yyyy-MM-dd HH:mm:ss.SSS Z 2013-13-13 23:59:59.999 +0100
If you make a slight mistake with the format, you can become the owner of a java.text.ParseException, and this is not a particularly pleasant achievement. Well, the short excursion into SimpleDateFormat is over - let's return to the translation of java string to date . SimpleDateFormat gives us such capabilities, and we will walk through this process step by step.
  1. Create a line from which you need to set the date:

    String strDate = "Sat, April 4, 2020";
  2. We create a new SimpleDateFormat object with a template that matches what we have in the string (otherwise we won’t be able to parse it):

    SimpleDateFormat formatter = new SimpleDateFormat("EEE, MMMM d, yyyy", Locale.ENGLISH);

    As you can see, we have a Locale argument here. If we omit it, it will use the default Locale, which is not always English.

    If the locale does not match the input string, then string data bound to the language, like ours Mon or April , will not be recognized and will throw a java.text.ParseException, even if the pattern matches.

    However, we don't have to specify the format if we are using a template that is not language specific. As an example - yyyy-MM-dd HH:mm:ss

  3. We create a date using a formatter, which in turn parses it from the input string:

    try {
      Date date = formatter.parse(strDate);
      System.out.println(date);
    }
    catch (ParseException e) {
      e.printStackTrace();
    }

    Console output:

    
    Sat Apr 04 00:00:00 EEST 2020

    Hmmm... But the format is no longer the same!

    To make the same format, we use the formatter again:

    System.out.println(formatter.format(date));

    Console output:

    
    Sat, April 4, 2020

SimpleDateFormat and Calendar

SimpleDateFormat allows you to format all Date and Calendar objects you create for later use. Let's consider such an interesting point as working with eras. To create a “BC” date, you need to use the Calendar.Era field. For example, let’s create a date indicating the Battle of Cannae, in which Hannibal defeated the army of Rome. This happened on August 2, 216 BC. e.:
public static void main(String[] args) {
   GregorianCalendar cannes = new GregorianCalendar(216, Calendar.AUGUST, 2);
   cannes.set(Calendar.ERA, GregorianCalendar.BC);

   DateFormat df = new SimpleDateFormat("dd MMM yyy GG");
   System.out.println(df.format(cannes.getTime()));
}
Here we used the SimpleDateFormat class to display the date in a format that is more understandable to us (as indicated above, the letters “GG” are responsible for displaying the era). Conclusion:

02 авг 216 до н.э.

Java Date Format

Here's another case. Let's assume that this date format does not suit us:

Sat Nov 25 10:42:12 MSK 2017
So here it is. Using our capabilities in java date format, you can change it to your own without much difficulty:
public static void main(String[] args) {

   SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, d MMMM yyyy");
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.roll(Calendar.MONTH, -2);
   System.out.println(dateFormat.format(calendar.getTime()));
}
Conclusion:

суббота, 25 Ноябрь 2017
Much better, right? :)
Comments
  • Popular
  • New
  • Old
You must be signed in to leave a comment
This page doesn't have any comments yet