CodeGym /Java Blog /Willekeurig /Hoe niet te verdwalen in de tijd: DateTime en Calendar
John Squirrels
Niveau 41
San Francisco

Hoe niet te verdwalen in de tijd: DateTime en Calendar

Gepubliceerd in de groep Willekeurig
Hoi! Vandaag gaan we werken met een nieuw gegevenstype dat we nog niet eerder zijn tegengekomen, namelijk datums. Hoe niet te verdwalen in de tijd: DateTime en Calendar - 1Ik denk niet dat ik hoef uit te leggen wat een date is. :) In principe zouden we de huidige datum en tijd kunnen opslaan in een gewone Java String.

public class Main {
   public static void main(String[] args) {

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
Maar deze aanpak heeft veel nadelen. De Stringklasse is ontworpen om met tekst te werken en de methoden zijn geschikt voor deze taak. Als we een datum op de een of andere manier moeten manipuleren (bijvoorbeeld 2 uur toevoegen), Stringwerkt dat niet zo goed. Of als we de huidige datum en tijd willen weergeven wanneer het programma wordt gecompileerd. Stringhelpt hier ook niet: tegen de tijd dat u de code schrijft en uitvoert, is de tijd veranderd en geeft de console de verkeerde informatie weer. Daarom hebben de makers van Java verschillende klassen voorzien voor het werken met datums en tijd. De eerste hiervan isjava.util.Date

Datum klasse

We hebben de volledige naam opgegeven, omdat een ander Java-pakket de java.sql.Dateclass. Haal ze niet door elkaar! Het eerste dat u moet weten, is dat het de datum opslaat als het aantal milliseconden dat is verstreken sinds 1 januari 1970. Dit tijdsysteem heeft zelfs zijn eigen naam: " Unix-time " Een nogal interessante benadering, zou ' Ben je het er niet mee eens? :) Het tweede dat de moeite waard is om te onthouden, is dit: als je een Dateobject maakt met de standaardconstructor, vertegenwoordigt het resultaat de huidige datum en tijd op het moment dat het object werd gemaakt . Weet je nog dat we zeiden dat een date voorgesteld als een Stringzou worstelen met zo'n taak? De Dateklas gaat er gemakkelijk mee om.

public class Main {
   public static void main(String[] args) {

       Date date = new Date();
       System.out.println(date);
   }
}
Voer deze code meerdere keren uit en u zult de tijd herhaaldelijk zien veranderen. :) Dit is mogelijk omdat de tijd wordt opgeslagen in milliseconden: het zijn extreem kleine tijdseenheden, dus de resultaten zijn zeer nauwkeurig. De Dateklasse een andere constructor: u kunt het exacte aantal milliseconden sinds 00:00 op 1 januari 1970 doorgeven aan de vereiste datum en er wordt een bijbehorend datumobject gemaakt:

public class Main {
   public static void main(String[] args) {

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
Console-uitvoer: vr 30 mei 04:20:12 GMT 2008 We krijgen 30 mei 2008. "Vrij" geeft de dag van de week aan (vrijdag, duh), en GMT is de tijdzone (Greenwich Mean Time). Milliseconden worden doorgegeven als longs, omdat het aantal milliseconden meestal niet past in een int. Dus, welke bewerkingen met datums moeten we mogelijk uitvoeren? Nou, het meest voor de hand liggende is natuurlijk vergelijking . Om te bepalen of de ene datum voor of na de andere komt. Dit kan op verschillende manieren worden gedaan. U kunt bijvoorbeeld de Date.getTime()methode aanroepen, die het aantal milliseconden teruggeeft dat is verstreken sinds middernacht op 1 januari 1970. Roep het gewoon aan op twee Date-objecten en vergelijk de resultaten:

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");
   }
}
Uitvoer: datum1 is eerder dan datum2. Maar er is ook een handigere manier, namelijk door gebruik te maken van speciale methoden van de klasse Date: before(), after()en equals(). Ze retourneren allemaal een booleaanse waarde. De before()methode controleert of onze datum eerder is dan de datum die als argument is doorgegeven:

public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

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

       System.out.println(date1.before(date2));
   }
}
Console-uitvoer: true Op dezelfde manier controleert de after()methode of onze datum later is dan de datum die als argument is doorgegeven:

public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

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

       System.out.println(date1.after(date2));
   }
}
Console-uitvoer: false In onze voorbeelden "zetten we het programma 2 seconden in de slaapstand", zodat de twee datums gegarandeerd verschillend zijn. Op snelle computers kan de tijd tussen het maken van date1en date2minder dan een milliseconde zijn, waardoor beide before()en after()onwaar retourneren. Maar in dit geval equals()zal de methode true retourneren! Het vergelijkt immers het aantal milliseconden sinds 00:00 op 1 januari 1970 voor elke datum. De objecten worden alleen als gelijk beschouwd als ze overeenkomen met de milliseconde :

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));
}
Hier is nog iets waar je op moet letten. Als u de documentatie voor de Dateklasse op de Oracle- website opent, ziet u dat veel van zijn methoden en constructors zijn gemarkeerd als Deprecated (dwz niet aanbevolen voor gebruik). Dit is wat de makers van Java te zeggen hebben over delen van klassen die zijn verouderd:
"Een programma-element met de annotatie @Deprecated is iets dat programmeurs niet wordt aangeraden om te gebruiken, meestal omdat het gevaarlijk is, of omdat er een beter alternatief is."
Dit betekent niet dat deze methoden helemaal niet kunnen worden gebruikt. Als u code probeert uit te voeren met behulp van verouderde methoden in een IDE, zal dit hoogstwaarschijnlijk werken. Neem bijvoorbeeld de verouderde Date.getHours()methode, die het aantal uren retourneert dat aan een Dateobject is gekoppeld.

public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());
}
Als u de code om 14:21 (14:21 PM) start, wordt het nummer 14 weergegeven. Zoals u kunt zien, is de verouderde methode doorgestreept, maar deze werkt nog steeds. Deze methoden worden niet verwijderd om de enorme hoeveelheid bestaande code die ze gebruikt niet te breken. Met andere woorden, deze methoden zijn niet "gebroken" of "verwijderd". Ze worden simpelweg niet aanbevolen voor gebruik omdat er een handiger alternatief beschikbaar is. Overigens vermeldt de documentatie specifiek dit alternatief:
Hoe niet te verdwalen in de tijd: DateTime en Calendar - 2
De meeste Datemethoden van de klasse zijn verplaatst naar de verbeterde en uitgebreide Calendarklasse. We maken hierna kennis met die klas. :)

Kalender klasse

JDK 1.1 introduceerde een nieuwe klasse: Calendar. Het maakte het werken met datums in Java iets gemakkelijker dan voorheen. De enige implementatie van de klasse Calendarwaarmee we zullen werken, is de GregorianCalendarklasse. Het implementeert de Gregoriaanse kalender, die door de meeste landen van de wereld wordt nageleefd. Het belangrijkste voordeel is dat het kan werken met datums in een handiger formaat. Het kan bijvoorbeeld:
  • Voeg een maand of dag toe aan de huidige datum
  • Controleer of het jaartal een schrikkeljaar is;
  • Retourneer individuele componenten van de datum (haal bijvoorbeeld het maandnummer uit een hele datum)
  • Het bevat ook een erg handig systeem van constanten (waarvan we er hieronder veel zullen zien).
Een andere belangrijke verbetering van de Calendarklasse is de Calendar.ERA- constante: u kunt een datum aangeven vóór de gewone jaartelling (BC - voor Christus) of in de gewone jaartelling (AD - Anno Domini). Laten we dit allemaal bekijken met voorbeelden. Laten we een calendarobject maken met de datum 25 januari 2017:

public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
In de Calendarklas (evenals de Dateklas overigens) beginnen maanden vanaf nul , dus geven we het getal 0 door als tweede argument. Als je met de klas werkt Calendar, is het belangrijk om te begrijpen dat dit niet meer is dan een kalender , geen individuele datum. Hoe niet te verdwalen in de tijd: DateTime en Calendar - 3 Een datum is slechts een paar cijfers die een specifiek tijdsinterval aangeven. Een kalender is een heel systeem waarmee je veel dingen met datums kunt doen. :) Dit is overduidelijk als je het Calendarobject probeert weer te geven: Uitvoer: java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/London",offset=0,dstSavings=0,useDaylight= false,overgangen=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=?] Kijk hoeveel informatie je krijgt ! Een kalender heeft een heleboel eigenschappen die een normale datum niet heeft, en ze worden allemaal weergegeven (zotoString()werkt de methode in deCalendarklas). Als u alleen een eenvoudige datum uit de kalender wilt halen, bijvoorbeeld eenDateobject, gebruikt u deCalendar.getTime()methode (de naam is niet de meest logische, maar wat kun je doen?):

public static void main(String[] args) {

   Calendar calendar = new GregorianCalendar(2017, 0 , 25);
   Date date = calendar.getTime();
   System.out.println(date);
}
Uitvoer: wo 25 jan. 00:00:00 GMT 2017 Nu hebben we de kalender genomen en "gereduceerd" tot een gewone datum. Laten we verder gaan. Naast het aanduiden van maanden met hun nummer, kunt u ook de constante veldwaardenCalendar van de klasse gebruiken . Deze constanten zijn statische velden van de klasse met een vooraf ingestelde waarde die niet kan worden gewijzigd. Dit is eigenlijk een nog betere optie, omdat het gebruik ervan de leesbaarheid van uw code verbetert. Calendar

public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
Calendar.JANUARY is een van de constanten die de maanden van het jaar vertegenwoordigen. Door deze benoemde constanten te gebruiken, zal niemand bijvoorbeeld vergeten dat het getal 3 april betekent, en niet de derde maand, die we graag maart noemen. Schrijf gewoon Calendar.APRIL , en je bent klaar. :) Alle kalendervelden (getal, maand, minuten, seconden, enz.) kunnen afzonderlijk worden gespecificeerd met behulp van deset()methode. Deze methode is erg handig, omdat deCalendarklasse een constante heeft voor elk veld en de resulterende code heel gemakkelijk te lezen is. In het laatste voorbeeld hebben we een datum gemaakt, maar er geen tijd voor ingesteld. Laten we de tijd instellen op 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());
}
Uitvoer: wo 25 jan 19:42:12 GMT 2017 We noemen de set()methode, het doorgeven van een constante (afhankelijk van het veld dat we willen wijzigen) en de nieuwe waarde voor het veld. Het blijkt dat deze set()methode een soort "super-setter" is die weet hoe de waarde niet alleen voor één veld moet worden ingesteld, maar voor veel velden. :) De Calendarklas gebruikt de add()methode om waarden op te tellen en af ​​te trekken. U geeft het veld door dat u wilt wijzigen, en een getal (precies hoeveel u wilt optellen/aftrekken van de huidige waarde). Laten we bijvoorbeeld een datum nemen die 2 maanden vóór de datum ligt die we hebben gemaakt:

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, pass a negative number
   System.out.println(calendar.getTime());
}
Uitvoer: vr 25 nov 19:42:12 GMT 2016 Zeer goed! We kregen de datum 2 maanden geleden. Hierdoor veranderde niet alleen de maand: ook het jaar veranderde van 2017 naar 2016. Natuurlijk wordt bij het omrekenen van datums het huidige jaar automatisch berekend zonder dat je dit handmatig hoeft bij te houden. Maar als u om de een of andere reden dit gedrag moet uitschakelen, kunt u dat doen. De roll()methode kan waarden optellen en aftrekken zonder de resterende waarden te beïnvloeden . Bijvoorbeeld als volgt:

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 deden precies hetzelfde als in het vorige voorbeeld: we namen 2 maanden vanaf de huidige datum. Maar nu doet de code iets anders: de maand is veranderd van januari in november, maar het jaar blijft ongewijzigd: 2017! Uitvoer: za 25 nov 10:42:12 GMT 2017 Verder gaan. Zoals we hierboven zeiden, kunnen we alle Calendarvelden afzonderlijk krijgen. Dit doen we met de get()methode:

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("Week in the month: " + calendar.get(Calendar.WEEK_OF_MONTH));// Week in this month?

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

   System.out.println("Hours: " + 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));

}
Uitvoer: Jaar: 2017 Maand: 0 Week in de maand: 5 Dag: 25 Uren: 10 Minuten: 42 Seconden: 12 Milliseconden: 0 Dus naast de Calendar"supersetter" van de klas is er ook een "supersetter" ". :) Een ander interessant aspect van deze les is natuurlijk het werken met tijdperken. Om een ​​"BC"-datum te maken, moet u het veld Calendar.ERA gebruiken. Laten we bijvoorbeeld een datum maken voor de Slag bij Cannae, waar Hannibal het Romeinse leger versloeg. Dit gebeurde op 2 augustus 216 voor Christus:

public static void main(String[] args) {
   GregorianCalendar cannae = new GregorianCalendar(216, Calendar.AUGUST, 2);
   cannae.set(Calendar.ERA, GregorianCalendar.BC);

   DateFormat df = new SimpleDateFormat("MMM dd, yyy GG");
   System.out.println(df.format(cannae.getTime()));
}
Hier hebben we de SimpleDateFormatklasse gebruikt om de datum af te drukken in een formaat dat voor ons gemakkelijker te begrijpen is (de letters "GG" geven aan dat we de jaartelling willen weergeven). Uitvoer: 2 augustus 216 v.Chr. De Calendarklasse heeft veel meer methoden en constanten. U kunt erover lezen in de documentatie . Als dit datumformaat za nov 25 10:42:12 GMT 2017 je niet bevalt, dan kun je het gebruiken SimpleDateFormatom het gemakkelijk te maken zoals je wilt.

public static void main(String[] args) {

   SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, MMMM d, 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()));
}
Uitvoer: zaterdag 25 november 2017 Dat is toch veel beter? :)
Opmerkingen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION