CodeGym /Java-blogg /Tilfeldig /Hvordan ikke gå seg vill i tide: DateTime og Kalender
John Squirrels
Nivå
San Francisco

Hvordan ikke gå seg vill i tide: DateTime og Kalender

Publisert i gruppen
Hei! I dag begynner vi å jobbe med en ny datatype vi ikke har møtt før, nemlig datoer. Hvordan ikke gå seg vill i tide: DateTime og Kalender - 1Jeg tror ikke jeg trenger å forklare hva en date er. :) I prinsippet kunne vi lagre gjeldende dato og klokkeslett i en vanlig Java-streng.

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

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
Men denne tilnærmingen har mange ulemper. Klassen Stringer laget for å jobbe med tekst, og metodene egner seg for denne oppgaven. Hvis vi trenger å manipulere en dato på en eller annen måte (legg til 2 timer, for eksempel), Stringfungerer ikke så bra. Eller om vi ønsker å vise gjeldende dato og klokkeslett når programmet er kompilert. Stringhjelper ikke her heller: når du skriver koden og kjører den, vil tiden ha endret seg og konsollen vil vise feil informasjon. Det er derfor Javas skapere ga flere klasser for å jobbe med datoer og klokkeslett. Den første av disse erjava.util.Date

Dato klasse

Vi spesifiserte det fulle navnet, fordi en annen Java-pakke har klassen java.sql.Date. Ikke bland dem sammen! Det første du trenger å vite om det er at det lagrer datoen som antall millisekunder som har gått siden 1. januar 1970. Dette tidssystemet har til og med sitt eget navn: " Unix-time " En ganske interessant tilnærming, ville' er du enig? :) Den andre tingen som er verdt å huske på er dette: Hvis du oppretter et Dateobjekt ved å bruke standardkonstruktøren, representerer resultatet gjeldende dato og klokkeslett i det øyeblikket objektet ble opprettet . Husker du at vi sa at en date representert som en Stringville slite med en slik oppgave? Klassen Datehåndterer det med letthet.

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

       Date date = new Date();
       System.out.println(date);
   }
}
Kjør denne koden flere ganger, og du vil se tiden endres gjentatte ganger. :) Dette er mulig fordi tiden er lagret som millisekunder: de er ekstremt små tidsenheter, så resultatene er svært nøyaktige. Klassen Dateen annen konstruktør: du kan sende det nøyaktige antallet millisekunder siden 00:00 1. januar 1970 til den nødvendige datoen, og et tilsvarende datoobjekt vil bli opprettet:

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

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
Konsollutgang: Fre 30. mai 04:20:12 GMT 2008 Vi får 30. mai 2008. "Fre" indikerer ukedagen (fredag, duh), og GMT er tidssonen (Greenwich Mean Time). Millisekunder sendes som longs, fordi antall millisekunder vanligvis ikke passer inn i en int. Så, hvilke operasjoner med datoer må vi kanskje utføre? Vel, det mest åpenbare er selvfølgelig sammenligning . For å finne ut om en date kommer før eller etter en annen. Dette kan gjøres på flere måter. Du kan for eksempel kalle Date.getTime()metoden, som returnerer antall millisekunder som har gått siden midnatt 1. januar 1970. Bare kall den på to Dato-objekter og sammenlign resultatene:

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");
   }
}
Utdata: dato1 er tidligere enn dato2 Men det er også en mer praktisk måte, dvs. ved å bruke spesielle metoder fra Dato-klassen: before(), after()og equals(). Alle returnerer en boolsk verdi. Metoden before()sjekker om datoen vår er tidligere enn datoen som ble sendt som argument:

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));
   }
}
Konsoll-utgang: sann På samme måte after()sjekker metoden for å se om datoen vår er senere enn datoen som ble sendt som argument:

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));
   }
}
Konsollutgang: usann I våre eksempler "setter vi programmet i dvale" i 2 sekunder, slik at de to datoene garantert er forskjellige. På raske datamaskiner kan tiden mellom opprettelsen av date1og date2være mindre enn ett millisekund, noe som fører til at både before()og after()returnerer falsk. Men i dette tilfellet equals()vil metoden returnere sann! Tross alt sammenligner den antall millisekunder siden klokken 00:00 1. januar 1970 for hver dato. Objektene anses som like bare hvis de samsvarer med millisekundet :

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));
}
Her er en annen ting du må være oppmerksom på. Hvis du åpner dokumentasjonen for Dateklassen på Oracle- nettstedet, vil du se at mange av metodene og konstruktørene har blitt merket som avviklet (dvs. ikke anbefalt for bruk). Her er hva Javas skapere har å si om deler av klasser som har blitt avviklet:
"Et programelement merket @Utviklet er noe programmerere ikke anbefales å bruke, vanligvis fordi det er farlig, eller fordi det finnes et bedre alternativ."
Dette betyr ikke at disse metodene ikke kan brukes i det hele tatt. Hvis du prøver å kjøre kode ved hjelp av utdaterte metoder i en IDE, vil det mest sannsynlig fungere. Tenk for eksempel på den utdaterte Date.getHours()metoden, som returnerer antall timer assosiert med et Dateobjekt.

public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());
}
Hvis du starter koden klokken 14:21 (14:21), vil den vise tallet 14. Som du kan se, er den utdaterte metoden krysset over, men den fungerer fortsatt. Disse metodene fjernes ikke for ikke å ødelegge den enorme mengden av eksisterende kode som bruker dem. Disse metodene er med andre ord verken "ødelagt" eller "fjernet". De anbefales rett og slett ikke for bruk fordi et mer praktisk alternativ er tilgjengelig. Dokumentasjonen nevner forøvrig spesifikt dette alternativet:
Hvordan ikke gå seg vill i tide: DateTime og Kalender - 2
De fleste av Dateklassens metoder har blitt flyttet til den forbedrede og utvidede Calendarklassen. Vi blir kjent med den timen neste gang. :)

Kalenderklasse

JDK 1.1 introduserte en ny klasse: Calendar. Det gjorde arbeidet med datoer i Java noe enklere enn før. Den eneste implementeringen av klassen Calendarvi skal jobbe med er GregorianCalendarklassen. Den implementerer den gregorianske kalenderen, som observeres av de fleste land i verden. Dens største fordel er at den kan fungere med datoer i et mer praktisk format. For eksempel kan det:
  • Legg til en måned eller dag til gjeldende dato
  • Sjekk om året er et skuddår;
  • Returner individuelle komponenter av datoen (trekk for eksempel ut månedsnummeret fra en hel dato)
  • Den inneholder også et veldig praktisk system med konstanter (mange av dem vil vi se nedenfor).
En annen viktig forbedring av Calendarklassen er dens Calendar.ERA konstant: du kan angi en dato før den vanlige epoken (f.Kr. - før Kristus) eller i den vanlige epoken (AD - Anno Domini). La oss se på alt dette med eksempler. La oss lage et calendarobjekt med datoen 25. januar 2017:

public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
I Calendarklassen (så vel som Dateklassen for den saks skyld) starter måneder fra null , så vi passerer tallet 0 som det andre argumentet. Når du arbeider med Calendarklassen, er det viktig å forstå at dette er nettopp det, en kalender , ikke en individuell dato. Hvordan ikke gå seg vill i tide: DateTime og Kalender - 3 En dato er bare noen få tall som indikerer et spesifikt tidsintervall. En kalender er et helt system som lar deg gjøre mange ting med datoer. :) Dette er rikelig tydelig hvis du prøver å vise objektet Calendar: Output: java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/London",offset=0,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_DAY_OF_YEAR? ,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?] Se hvor mye informasjon du får ! En kalender har en haug med egenskaper som en vanlig dato ikke har, og alle vises (sliktoString()fungerer metoden iCalendarklassen). Hvis du bare trenger å få en enkel dato fra kalenderen, altså etDateobjekt, brukCalendar.getTime()metode (navnet er ikke det mest logiske, men hva kan du gjøre?):

public static void main(String[] args) {

   Calendar calendar = new GregorianCalendar(2017, 0 , 25);
   Date date = calendar.getTime();
   System.out.println(date);
}
Utgang: Wed Jan 25 00:00:00 GMT 2017 Nå har vi tatt kalenderen og "redusert den" til en ordinær dato. La oss gå videre. I tillegg til å angi måneder etter antall, kan du bruke Calendarklassens konstante feltverdier . Disse konstantene er statiske felt i Calendarklassen med en forhåndsinnstilt verdi som ikke kan endres. Dette er faktisk et enda bedre alternativ, fordi bruk av dem forbedrer lesbarheten til koden din.

public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
Kalender.JANUAR er en av konstantene som representerer månedene i året. Ved å bruke disse navngitte konstantene vil ingen glemme for eksempel at tallet 3 betyr april, og ikke tredje måned, som vi gjerne kaller mars. Bare skriv Kalender.APRIL , så er du ferdig. :) Alle kalenderfelt (tall, måned, minutter, sekunder osv.) kan spesifiseres separat ved hjelp av metodenset(). Denne metoden er veldig praktisk, fordiCalendarklassen har en konstant for hvert felt, og den resulterende koden er veldig lett å lese. I det siste eksemplet opprettet vi en dato, men satte ikke noe tidspunkt for den. La oss stille klokken 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());
}
Utdata: Wed Jan 25 19:42:12 GMT 2017 Vi kaller set()metoden, og sender en konstant (avhengig av feltet vi ønsker å endre) og den nye verdien for feltet. Det viser seg at denne set()metoden er en slags "super-setter" som vet hvordan man setter verdien ikke bare for ett felt, men for mange felt. :) CalendarKlassen bruker add()metoden for å addere og subtrahere verdier. Du sender inn feltet du ønsker å endre, og et tall (nøyaktig hvor mye du vil legge til/trekke fra fra gjeldende verdi). La oss for eksempel få en dato som er 2 måneder før datoen vi opprettet:

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());
}
Utgang: Fre 25. nov 19:42:12 GMT 2016 Veldig bra! Vi fikk datoen for 2 måneder siden. Dette førte ikke bare til at måneden endret seg: året endret seg også fra 2017 til 2016. Selvfølgelig, når du konverterer datoer, beregnes gjeldende år automatisk uten at du trenger å holde styr på det manuelt. Men hvis du av en eller annen grunn trenger å deaktivere denne oppførselen, kan du gjøre det. Metoden roll()kan legge til og trekke fra verdier uten å påvirke de gjenværende verdiene . For eksempel slik:

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());
}
Vi gjorde nøyaktig det samme som i forrige eksempel: vi tok 2 måneder fra gjeldende dato. Men nå gjør koden noe annerledes: måneden har endret seg fra januar til november, men året forblir uendret—2017! Utgang: Lør 25. nov 10:42:12 GMT 2017 Går videre. Som vi sa ovenfor, kan vi få alle Calendarfeltene separat. Dette gjør vi med get()metoden:

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));

}
Utgang: År: 2017 Måned: 0 Uke i måneden: 5 Dag: 25 Timer: 10 minutter: 42 sekunder: 12 millisekunder: 0 Så, i tillegg til Calendarklassens "super-setter", er det også en "super-getter" ". :) Selvfølgelig er et annet interessant aspekt ved denne klassen å jobbe med epoker. For å lage en "BC"-dato, må du bruke Calendar.ERA- feltet La oss for eksempel lage en dato for slaget ved Cannae, der Hannibal beseiret den romerske hæren. Dette skjedde 2. august 216 f.Kr.:

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()));
}
Her brukte vi SimpleDateFormatklassen til å skrive ut datoen i et format som er lettere for oss å forstå (bokstavene "GG" indikerer at vi ønsker at epoken skal vises). Utgang: 2. august 216 f.Kr. Klassen Calendarhar mange flere metoder og konstanter. Du kan lese om dem i dokumentasjonen . Hvis du ikke liker dette datoformatet Sat Nov 25 10:42:12 GMT 2017, kan du bruke det SimpleDateFormattil å enkelt gjøre det til det du vil ha det til.

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()));
}
Utgang: lørdag 25. november 2017 Det er mye bedre, ikke sant? :)
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION