Java Data Time
Datum
Zahlreiche Methoden der Date Objekte sind seit einiger Zeit deprecated. Mit der Hilfe der Calendar Klasse kann man weiterhin auf die entsprechenden Datumsfelder zugreifen:
Calendar lCal=Calendar.getInstance();
lCal.setTime(lCurrentDate);
lCal.get(Calendar.YEAR);
lCal.get(Calendar.MONTH);
lCal.get(Calendar.DAY_OF_MONTH);
Und entsprechend lässt sich das Datum auch manipulieren
lToday.set(Calendar.HOUR_OF_DAY, 23);
lToday.set(Calendar.MINUTE, 59);
lToday.set(Calendar.SECOND, 0);
lToday.set(Calendar.MILLISECOND, 0);
Date lNewDate=lToday.getTime();
Möchte man von einem gegebenen Datum einige Tage abziehen oder addieren geht das so
Calendar calendar = new GregorianCalendar();
// remove timezone
Date cleanDate=new Date(yourDate.getTime());
calendar.setTime(cleanDate);
calendar.add(Calendar.DAY_OF_MONTH, -14);
Date lNewDate=calendar.getTime();
So kann man ein Datum in einen schönen String umwandeln (format()) oder aus einem beliebigen String ein Datum erzeugen (parse())
...
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String s=f.format(d);
f.setLenient(false);
Date d2=f.parse(s);
For example for LocalDate you need to use the DateTimeFormatter instead of the SimpleDateFormat.
// to date
LocalDate date = LocalDate.parse("2021-12-31, f);
// to string
String s=f.format(date);
There are some predefined formats where you can learn / steal from
Format | Output |
---|---|
DateTimeFormatter.BASIC_ISO_DATE | 20190916+0200 |
DateTimeFormatter.ISO_LOCAL_TIME | 13:31:47.3 |
DateTimeFormatter.ISO_OFFSET_DATE_TIME | 2019-09-16T13:31:47.3+02:00 |
DateTimeFormatter.ISO_OFFSET_DATE | 2019-09-16+02:00 |
DateTimeFormatter.ISO_OFFSET_TIME | 13:31:47.3+02:00 |
DateTimeFormatter.ISO_TIME | 13:31:47.3+02:00 |
DateTimeFormatter.ISO_OFFSET_TIME | 13:31:47.3+02:00 |
DateTimeFormatter.ISO_DATE | 2019-09-16+02:00 |
DateTimeFormatter.ISO_DATE_TIME | 2019-09-16T13:31:47.3+02:00[Europe/Berlin] |
DateTimeFormatter.ISO_INSTANT | 2019-09-16T11:31:47.300Z |
DateTimeFormatter.ISO_LOCAL_DATE | 2019-09-16 |
DateTimeFormatter.ISO_LOCAL_DATE_TIME | 2019-09-16T13:31:47.3 |
DateTimeFormatter.ISO_ORDINAL_DATE | 2019-259+02:00 |
DateTimeFormatter.ISO_WEEK_DATE | 2019-W38-1+02:00 |
DateTimeFormatter.ISO_ZONED_DATE_TIME | 2019-09-16T13:31:47.3+02:00[Europe/Berlin] |
Mit dem Datum kann man in Java viel Spaß haben. Angenommen man hat zwei Datumsobjekte
java.util.Date date1;
java.util.Date date2;
Eines davon ist wirklich vom Typ Date, das andere ein Timestamp (ein Erbe von Date)
date2=new java.sql.Timestamp(time1);
Das ist keine künstliche Situation, das passiert z.B. schnell wenn man ein Datum per Hibernate in einer Datenbank persistiert und wieder ausliest. Beide zeigen auf exakt dieselbe Uhrzeit und sind sogar equal
date2.getTime(); // 1376639746195
date1.equals(date2); // true
Was passiert wohl, wenn man beide vergleicht?
Die ersten der beiden gleichen Daten ist also größer!
Testen wir doch mal
date2.equals(date1); // false
Die Ursache ist offenbar, dass die Genauigkeit von Timestamp eigentlich nicht genau genug für Millisekunden ist. Also entfernen wir im Date doch auch mal die Millisekunden (die letzten 3 Stellen)
long time2=1376639746000L;
date1=new java.util.Date(time2);
Und schon findet compareTo, dass beide gleich sind.
date2.getTime(); // 1376639746195
date1.compareTo(date2); // 0
Aber sind sie eigentlich trotz der abweichenden getTime() Werte noch equals?
date2.equals(date1); // false
Es hilft hier nur, in beiden den Millisekundenanteil zu streichen. Kleiner Auszug aus dem JavaDoc von compareTo()
String to Instant, String to LocalDate, LocalDate to LocalDateTime, LocalDateTime to Instant
final LocalDate d = LocalDate.of(2012, 2, 2);
final LocalDateTime t = LocalDateTime.of(a, LocalTime.MIDNIGHT);
final Instant ti = t.toInstant(ZoneOffset.UTC);
Zeitzonen
// you. For people in different timezones that day starts and end sooner or later than for you
final LocalDate christmas = LocalDate.of(2016, 12, 24);
// a time without a timezone. E.g. when this is on your watch the new year might start for you. When your watch
// shows this time highly depends on the timezone you are in
final LocalDateTime startOfYear = LocalDateTime.of(2016, 12, 24, 0, 0);
// this is a point in time with a timezone. This is for everybody the same moment.
final ZonedDateTime callMeAt = ZonedDateTime.of(2016, 02, 07, 16, 15, 0, 0, ZoneId.of("Europe/Berlin"));
// for convenience you can get it in your timezone as well (still the same moment in time)
final ZonedDateTime callMeAt2 = callMeAt.withZoneSameInstant(ZoneId.of("Brazil/East"));
// or you can keep the time and just change the time zone (this will be a differnt moment in time)
final ZonedDateTime callMeAt3 = callMeAt.withZoneSameLocal(ZoneId.of("Brazil/East"));
Measure time inside code
import org.slf4j.LoggerFactory;
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Slf4jReporter;
import com.codahale.metrics.Snapshot;
import com.codahale.metrics.Timer;
import com.codahale.metrics.Timer.Context;
public class TimerTest {
private final Meter requestFrequency;
final Timer timerTotal;
final Timer timerFirst;
final Timer timerSecond;
public TimerTest() {
final MetricRegistry metricsRegistry = new MetricRegistry();
requestFrequency = metricsRegistry.meter("request-frequency");
timerTotal = metricsRegistry.timer("total");
timerFirst = metricsRegistry.timer("first");
timerSecond = metricsRegistry.timer("second");
}
public void handleRequest() {
// counts and tells you later how many we had per second
requestFrequency.mark();
hardWork();
}
public void doLongTimeStuff() {
// use Closable to stop time under every condition
try (Context total = timerTotal.time()) {
// start and stop manually not via Closable
final Context first = timerFirst.time();
hardWork();
first.stop();
final Context second = timerSecond.time();
hardWork();
second.stop();
}
}
...
Use this to log the current timers periodically
final ConsoleReporter reporter = ConsoleReporter.forRegistry(metricsRegistry).convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS).build();
reporter.start(1, TimeUnit.SECONDS);
// logs every second everythging to the log file
final Slf4jReporter slf4jLogger = Slf4jReporter.forRegistry(metricsRegistry)
.outputTo(LoggerFactory.getLogger(TimerTest.class)).convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS).build();
slf4jLogger.start(1, TimeUnit.MINUTES);