/* * Copyright 2008-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.nominanuda.zen.time; import static java.time.temporal.ChronoField.INSTANT_SECONDS; import static java.time.temporal.ChronoField.MILLI_OF_SECOND; import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAccessor; import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.concurrent.atomic.AtomicLong; import javax.annotation.concurrent.ThreadSafe; import javax.xml.datatype.DatatypeFactory; @ThreadSafe public class SysClock { public static final SysClock CLOCK = new SysClock(); /** * @return static alias of {@link #getWallClockEpochUtcMillis()} */ public static long now() { return CLOCK.systime(); } /** * * @return epoch in millis with a coarse approximation up to 10ms * it is implemented with performance and possibly context switching avoidance in mind */ public long getWallClockEpochUtcMillis() { return System.currentTimeMillis(); } /** * * @return alias of {@link #getWallClockEpochUtcMillis()} */ public long systime() { return getWallClockEpochUtcMillis(); } public TimeDiff start() { return new TimeDiff(System.nanoTime()); } @ThreadSafe public static final class TimeDiff { private static final long UNSET_VALUE = -1l; private final long start; private final AtomicLong end = new AtomicLong(UNSET_VALUE); private AtomicLong diff = new AtomicLong(UNSET_VALUE); public TimeDiff(long start) { this.start = start; } public TimeDiff stop() throws IllegalStateException { stop(true); return this; } public boolean stopIfRunning() { return stop(false); } public boolean isStopped() { return end.get() != UNSET_VALUE; } public boolean isRunning() { return end.get() == UNSET_VALUE; } private boolean stop(boolean throw_) throws IllegalStateException { long l = System.nanoTime(); if(! end.compareAndSet(UNSET_VALUE, l)) { if(throw_) { throw new IllegalStateException("TimeDiff already stopped"); } else { return false; } } else { diff.set(l - start); return true; } } public long getNano() throws IllegalStateException { long l = diff.get(); if(l == UNSET_VALUE) { throw new IllegalStateException("TimeDiff still running"); } else { return l; } } public long getMicro() throws IllegalStateException { return getNano() / 1000; } public long getMillis() throws IllegalStateException { return getNano() / 1000000; } } /** * * @param task * @return task execution time in millis */ public long elapsed(Runnable task) { TimeDiff s = start(); task.run(); return s.stop().getMillis(); } //from DateTimeHelper private final DatatypeFactory dtf; { try { dtf = DatatypeFactory.newInstance(); } catch (Exception e) { throw new IllegalStateException(e); } } public final String ISO_EPOCH_DT_SEC = "1970-01-01T00:00:00Z"; private static final DateTimeFormatter isoUtcSecs = DateTimeFormatter.ISO_INSTANT; private String toISO8601UtcSecs(Instant dt) { return isoUtcSecs.format(dt); } public String toISO8601UtcSecs(long utcEpochMillis) { return toISO8601UtcSecs(Instant.ofEpochMilli(utcEpochMillis)); } public String nowToISO8601UtcSecs() { return toISO8601UtcSecs(now()); } private long toEpochMillis(TemporalAccessor ta) { return ta.get(INSTANT_SECONDS) * 1000 + ta.get(MILLI_OF_SECOND); } public long fromISO8601UtcSecs(String isoDt) throws IllegalArgumentException { return toEpochMillis(isoUtcSecs.parse(isoDt)); } public CronExpr createCronExpr(String cronExpression, String timeZone) { return new CronExpr(cronExpression, timeZone); } public CronExpr createUtcCronExpr(String cronExpression) { return new CronExpr(cronExpression); } public boolean isValidCronExpr(String cronExpression) { return CronExpression.isValidExpression(cronExpression); } /** * @return the millis from epoch GMT or -1 if format is not recognized */ public long parseHttpDate822(String val) { val = val.trim(); if (val.endsWith(" GMT")) { val = val.substring(0, val.length() - 4); } for(DateTimeFormatter fmt : STD_RFC_822_FMTS) { try { return toEpochMillis(fmt.parse(val)); } catch(IllegalArgumentException e) { } } for(DateTimeFormatter fmt : NON_STD_RFC_822_FMTS) { try { return toEpochMillis(fmt.parse(val)); } catch(IllegalArgumentException e) { } } return -1; } private final static List<DateTimeFormatter> STD_RFC_822_FMTS = Arrays.asList(new DateTimeFormatter[] { DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz").withLocale(Locale.US), DateTimeFormatter.ofPattern("EEE, dd-MMM-yy HH:mm:ss").withLocale(Locale.US).withZone(ZoneId.of("UTC")), DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy").withLocale(Locale.US).withZone(ZoneId.of("UTC")) }); private final static List<DateTimeFormatter> NON_STD_RFC_822_FMTS = Arrays.asList(new DateTimeFormatter[] { DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss").withLocale(Locale.US).withZone(ZoneId.of("UTC")), DateTimeFormatter.ofPattern("EEE dd MMM yyyy HH:mm:ss zzz").withLocale(Locale.US), DateTimeFormatter.ofPattern("EEE dd MMM yyyy HH:mm:ss").withLocale(Locale.US).withZone(ZoneId.of("UTC")), DateTimeFormatter.ofPattern("EEE MMM dd yyyy HH:mm:ss zzz").withLocale(Locale.US), DateTimeFormatter.ofPattern("EEE MMM dd yyyy HH:mm:ss").withLocale(Locale.US).withZone(ZoneId.of("UTC")), DateTimeFormatter.ofPattern("EEE MMM-dd-yyyy HH:mm:ss zzz").withLocale(Locale.US), DateTimeFormatter.ofPattern("EEE MMM-dd-yyyy HH:mm:ss").withLocale(Locale.US).withZone(ZoneId.of("UTC")), DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm:ss zzz").withLocale(Locale.US), DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm:ss").withLocale(Locale.US).withZone(ZoneId.of("UTC")), DateTimeFormatter.ofPattern("dd-MMM-yy HH:mm:ss zzz").withLocale(Locale.US), DateTimeFormatter.ofPattern("dd-MMM-yy HH:mm:ss").withLocale(Locale.US).withZone(ZoneId.of("UTC")), DateTimeFormatter.ofPattern("MMM dd HH:mm:ss yyyy zzz").withLocale(Locale.US), DateTimeFormatter.ofPattern("MMM dd HH:mm:ss yyyy").withLocale(Locale.US).withZone(ZoneId.of("UTC")), DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy zzz").withLocale(Locale.US), DateTimeFormatter.ofPattern("EEE, MMM dd HH:mm:ss yyyy zzz").withLocale(Locale.US), DateTimeFormatter.ofPattern("EEE, MMM dd HH:mm:ss yyyy").withLocale(Locale.US).withZone(ZoneId.of("UTC")), DateTimeFormatter.ofPattern("EEE, dd-MMM-yy HH:mm:ss zzz").withLocale(Locale.US), DateTimeFormatter.ofPattern("EEE dd-MMM-yy HH:mm:ss zzz").withLocale(Locale.US), DateTimeFormatter.ofPattern("EEE dd-MMM-yy HH:mm:ss").withLocale(Locale.US).withZone(ZoneId.of("UTC")), }); public String msecToXsdDur(long msDur) { return dtf.newDuration(msDur).toString(); } }