
com.twineworks.tweakflow.std.Time Maven / Gradle / Ivy
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Twineworks GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.twineworks.tweakflow.std;
import com.twineworks.tweakflow.lang.errors.LangError;
import com.twineworks.tweakflow.lang.errors.LangException;
import com.twineworks.tweakflow.lang.types.Types;
import com.twineworks.tweakflow.lang.values.*;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.format.ResolverStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.WeekFields;
import java.util.Collections;
import java.util.TimeZone;
public final class Time {
private static Value periodToDict(Period period) {
return Values.makeDict(
"years", Values.make(period.getYears()),
"months", Values.make(period.getMonths()),
"days", Values.make(period.getDays())
);
}
private static Value durationToDict(Duration duration) {
return Values.makeDict(
"seconds", Values.make(duration.getSeconds()),
"nano_seconds", Values.make(duration.getNano())
);
}
public static boolean isValidTimeZone(final String timeZone) {
try {
ZoneId id = ZoneId.of(timeZone);
return id != null;
}
catch(DateTimeException e){
return false;
}
// final String DEFAULT_GMT_TIMEZONE = "GMT";
// if (timeZone.equals(DEFAULT_GMT_TIMEZONE)) {
// return true;
// } else {
// // if custom time zone is invalid,
// // time zone id returned is always "GMT" by default
// String id = TimeZone.getTimeZone(timeZone).getID();
// return !id.equals(DEFAULT_GMT_TIMEZONE);
// }
}
// function unix_timestamp(datetime x) -> long
public static final class unixTimestamp implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getInstant().toEpochMilli()/1000L);
}
}
// function unix_timestamp(datetime x) -> long
public static final class unixTimestampMs implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getInstant().toEpochMilli());
}
}
// function years_between: (datetime start_inclusive, datetime end_exclusive) -> long
public static final class yearsBetween implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value startInclusive, Value endExclusive) {
if (startInclusive == Values.NIL) return Values.NIL;
if (endExclusive == Values.NIL) return Values.NIL;
DateTimeValue start = startInclusive.dateTime();
DateTimeValue end = endExclusive.dateTime();
return Values.make(ChronoUnit.YEARS.between(start.getZoned(), end.getZoned()));
}
}
// function months_between: (datetime start_inclusive, datetime end_exclusive) -> long
public static final class monthsBetween implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value startInclusive, Value endExclusive) {
if (startInclusive == Values.NIL) return Values.NIL;
if (endExclusive == Values.NIL) return Values.NIL;
DateTimeValue start = startInclusive.dateTime();
DateTimeValue end = endExclusive.dateTime();
return Values.make(ChronoUnit.MONTHS.between(start.getZoned(), end.getZoned()));
}
}
// function days_between: (datetime start_inclusive, datetime end_exclusive) -> long
public static final class daysBetween implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value startInclusive, Value endExclusive) {
if (startInclusive == Values.NIL) return Values.NIL;
if (endExclusive == Values.NIL) return Values.NIL;
DateTimeValue start = startInclusive.dateTime();
DateTimeValue end = endExclusive.dateTime();
return Values.make(ChronoUnit.DAYS.between(start.getZoned(), end.getZoned()));
}
}
// function hours_between: (datetime start_inclusive, datetime end_exclusive) -> long
public static final class hoursBetween implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value startInclusive, Value endExclusive) {
if (startInclusive == Values.NIL) return Values.NIL;
if (endExclusive == Values.NIL) return Values.NIL;
DateTimeValue start = startInclusive.dateTime();
DateTimeValue end = endExclusive.dateTime();
return Values.make(ChronoUnit.HOURS.between(start.getZoned(), end.getZoned()));
}
}
// function minutes_between: (datetime start_inclusive, datetime end_exclusive) -> long
public static final class minutesBetween implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value startInclusive, Value endExclusive) {
if (startInclusive == Values.NIL) return Values.NIL;
if (endExclusive == Values.NIL) return Values.NIL;
DateTimeValue start = startInclusive.dateTime();
DateTimeValue end = endExclusive.dateTime();
return Values.make(ChronoUnit.MINUTES.between(start.getZoned(), end.getZoned()));
}
}
// function seconds_between: (datetime start_inclusive, datetime end_exclusive) -> long
public static final class secondsBetween implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value startInclusive, Value endExclusive) {
if (startInclusive == Values.NIL) return Values.NIL;
if (endExclusive == Values.NIL) return Values.NIL;
DateTimeValue start = startInclusive.dateTime();
DateTimeValue end = endExclusive.dateTime();
return Values.make(ChronoUnit.SECONDS.between(start.getZoned(), end.getZoned()));
}
}
// function periods_between: function(datetime start_inclusive, datetime end_exclusive) -> dict
public static final class periodBetween implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value startInclusive, Value endExclusive) {
if (startInclusive == Values.NIL) return Values.NIL;
if (endExclusive == Values.NIL) return Values.NIL;
DateTimeValue start = startInclusive.dateTime();
DateTimeValue end = endExclusive.dateTime();
return periodToDict(
Period.between(start.getLocal().toLocalDate(), end.getLocal().toLocalDate())
);
}
}
// function duration_between: (datetime start_inclusive, datetime end_exclusive) -> dict
public static final class durationBetween implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value startInclusive, Value endExclusive) {
if (startInclusive == Values.NIL) return Values.NIL;
if (endExclusive == Values.NIL) return Values.NIL;
DateTimeValue start = startInclusive.dateTime();
DateTimeValue end = endExclusive.dateTime();
return durationToDict(
Duration.between(start.getZoned(), end.getZoned())
);
}
}
// function add_period(datetime start, long years, long months, long days) -> datetime
public static final class addPeriod implements UserFunction, Arity4UserFunction {
@Override
public Value call(UserCallContext context, Value start, Value years, Value months, Value days) {
if (start == Values.NIL) return Values.NIL;
if (years == Values.NIL) return Values.NIL;
if (months == Values.NIL) return Values.NIL;
if (days == Values.NIL) return Values.NIL;
Long yearsLong = years.longNum();
Long monthsLong = months.longNum();
Long daysLong = days.longNum();
DateTimeValue startTime = start.dateTime();
try {
return Values.make(new DateTimeValue(
startTime.getZoned()
.plusYears(yearsLong)
.plusMonths(monthsLong)
.plusDays(daysLong)));
} catch (DateTimeException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, e.getMessage());
}
}
}
// function add_duration: (datetime start, long seconds=0, long nano_of_second=0) -> datetime
public static final class addDuration implements UserFunction, Arity3UserFunction {
@Override
public Value call(UserCallContext context, Value start, Value seconds, Value nanoOfSecond) {
if (start == Values.NIL) return Values.NIL;
if (seconds == Values.NIL) return Values.NIL;
if (nanoOfSecond == Values.NIL) return Values.NIL;
Long secondsLong = seconds.longNum();
Long nanosLong = nanoOfSecond.longNum();
DateTimeValue startTime = start.dateTime();
try {
return Values.make(new DateTimeValue(
startTime.getZoned()
.plusSeconds(secondsLong)
.plusNanos(nanosLong)));
} catch (DateTimeException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, e.getMessage());
}
}
}
// function year(datetime x) -> long
public static final class year implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getZoned().getYear());
}
}
// function month(datetime x) -> long
public static final class month implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getZoned().getMonthValue());
}
}
// function end_of_month(datetime x, long offset=nil) -> long via {:class "com.twineworks.tweakflow.std.Time$endOfMonth"}
public static final class endOfMonth implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value x, Value offset) {
if (x == Values.NIL) return Values.NIL;
if (offset == Values.NIL) return Values.NIL;
long offsetMonths = offset.longNum();
return Values.make(x.dateTime().getZoned()
.withDayOfMonth(1)
.plusMonths(1+offsetMonths)
.plusDays(-1)
);
}
}
// function day_of_month(datetime x) -> long via {:class "com.twineworks.tweakflow.std.Time$dayOfMonth"}
public static final class dayOfMonth implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getZoned().getDayOfMonth());
}
}
// function day_of_year(datetime x) -> long via {:class "com.twineworks.tweakflow.std.Time$dayOfYear"}
public static final class dayOfYear implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getZoned().getDayOfYear());
}
}
// function day_of_week(datetime x) -> long via {:class "com.twineworks.tweakflow.std.Time$dayOfWeek"}
public static final class dayOfWeek implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getZoned().getDayOfWeek().getValue());
}
}
// function hour(datetime x) -> long via {:class "com.twineworks.tweakflow.std.Time$hour"}
public static final class hour implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getZoned().getHour());
}
}
// function minute(datetime x) -> long via {:class "com.twineworks.tweakflow.std.Time$minute"}
public static final class minute implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getZoned().getMinute());
}
}
// function second(datetime x) -> long via {:class "com.twineworks.tweakflow.std.Time$second"}
public static final class second implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getZoned().getSecond());
}
}
// function nano_of_second(datetime x) -> long via {:class "com.twineworks.tweakflow.std.Time$nanoOfSecond"}
public static final class nanoOfSecond implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getZoned().getNano());
}
}
// function week_of_year(datetime x) -> long via {:class "com.twineworks.tweakflow.std.Time$weekOfYear"}
public static final class weekOfYear implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getZoned().getLong(WeekFields.ISO.weekOfWeekBasedYear()));
}
}
// function offset_seconds(datetime x) -> long via {:class "com.twineworks.tweakflow.std.Time$offsetSeconds"}
public static final class offsetSeconds implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getZoned().getOffset().get(ChronoField.OFFSET_SECONDS));
}
}
// function zone(datetime x) -> string via {:class "com.twineworks.tweakflow.std.Time$zone"}
public static final class zone implements UserFunction, Arity1UserFunction {
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(x.dateTime().getZoned().getZone().getId());
}
}
public static final class formatter_impl implements UserFunction, Arity1UserFunction {
private final DateTimeFormatter formatter;
public formatter_impl(DateTimeFormatter formatter) {
this.formatter = formatter;
}
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
return Values.make(formatter.format(x.dateTime().getZoned()));
}
}
// (string pattern, string lang) -> function
public static final class formatter implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value pattern, Value lang) {
if (pattern == Values.NIL) {
throw new LangException(LangError.NIL_ERROR, "pattern cannot be nil");
}
if (lang == Values.NIL) {
throw new LangException(LangError.NIL_ERROR, "language tag cannot be nil");
}
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern.string(), java.util.Locale.forLanguageTag(lang.string()));
return Values.make(
new UserFunctionValue(
new FunctionSignature(Collections.singletonList(
new FunctionParameter(0, "x", Types.DATETIME, Values.NIL)),
Types.STRING),
new formatter_impl(formatter)));
} catch (IllegalArgumentException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "invalid datetime format pattern: " + e.getMessage());
}
}
}
public static final class parser_impl implements UserFunction, Arity1UserFunction {
private final DateTimeFormatter formatter;
public parser_impl(DateTimeFormatter formatter) {
this.formatter = formatter;
}
@Override
public Value call(UserCallContext context, Value x) {
if (x == Values.NIL) return Values.NIL;
DateTimeValue dt = null;
try {
dt = new DateTimeValue(ZonedDateTime.parse(x.string(), formatter));
} catch (DateTimeParseException e1) {
try {
dt = new DateTimeValue(LocalDateTime.parse(x.string(), formatter).atZone(formatter.getZone()));
} catch (DateTimeParseException e2) {
try {
dt = new DateTimeValue(LocalDate.parse(x.string(), formatter).atStartOfDay().atZone(formatter.getZone()));
} catch (DateTimeParseException e3) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, e3.getMessage());
}
}
}
return Values.make(dt);
}
}
// (string pattern, string lang, string default_tz, boolean lenient) -> function
public static final class parser implements UserFunction, Arity4UserFunction {
@Override
public Value call(UserCallContext context, Value pattern, Value lang, Value default_tz, Value lenient) {
if (pattern == Values.NIL) {
throw new LangException(LangError.NIL_ERROR, "pattern cannot be nil");
}
if (lang == Values.NIL) {
throw new LangException(LangError.NIL_ERROR, "language tag cannot be nil");
}
if (lenient == Values.NIL) {
throw new LangException(LangError.NIL_ERROR, "lenient flag cannot be nil");
}
if (default_tz == Values.NIL) {
throw new LangException(LangError.NIL_ERROR, "default_tz cannot be nil");
}
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern.string(), java.util.Locale.forLanguageTag(lang.string()));
if (lenient == Values.TRUE) {
formatter = formatter.withResolverStyle(ResolverStyle.LENIENT);
} else {
formatter = formatter.withResolverStyle(ResolverStyle.STRICT);
}
try {
formatter = formatter.withZone(ZoneId.of(default_tz.string()));
} catch (DateTimeException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "invalid time zone: " + e.getMessage());
}
return Values.make(
new UserFunctionValue(
new FunctionSignature(Collections.singletonList(
new FunctionParameter(0, "x", Types.STRING, Values.NIL)),
Types.DATETIME),
new parser_impl(formatter)));
} catch (IllegalArgumentException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "invalid datetime format pattern: " + e.getMessage());
}
}
}
// () -> list
public static final class zones implements UserFunction, Arity0UserFunction {
@Override
public Value call(UserCallContext context) {
ListValue list = new ListValue();
for (String tz : ZoneId.getAvailableZoneIds()) {
list = list.append(Values.make(tz));
}
return Values.make(list);
}
}
// function with_year(datetime x, long year) -> datetime
public static final class withYear implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value x, Value year) {
if (x == Values.NIL) return Values.NIL;
if (year == Values.NIL) return Values.NIL;
Long y = year.longNum();
if ((long) y.intValue() != y) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "year value out of range: " + y);
}
DateTimeValue t = x.dateTime();
try {
return Values.make(new DateTimeValue(t.getZoned().withYear(y.intValue())));
} catch (DateTimeException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, e.getMessage());
}
}
}
// function with_month(datetime x, long month) -> datetime
public static final class withMonth implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value x, Value month) {
if (x == Values.NIL) return Values.NIL;
if (month == Values.NIL) return Values.NIL;
Long m = month.longNum();
if ((long) m.intValue() != m) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "month value out of range: " + m);
}
DateTimeValue t = x.dateTime();
try {
return Values.make(new DateTimeValue(t.getZoned().withMonth(m.intValue())));
} catch (DateTimeException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, e.getMessage());
}
}
}
// function with_day_of_month(datetime x, long day_of_month) -> datetime
public static final class withDayOfMonth implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value x, Value day_of_month) {
if (x == Values.NIL) return Values.NIL;
if (day_of_month == Values.NIL) return Values.NIL;
Long d = day_of_month.longNum();
if ((long) d.intValue() != d) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "day_of_month value out of range: " + d);
}
DateTimeValue t = x.dateTime();
try {
return Values.make(new DateTimeValue(t.getZoned().withDayOfMonth(d.intValue())));
} catch (DateTimeException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, e.getMessage());
}
}
}
// function with_hour(datetime x, long hour) -> datetime
public static final class withHour implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value x, Value hour) {
if (x == Values.NIL) return Values.NIL;
if (hour == Values.NIL) return Values.NIL;
Long d = hour.longNum();
if ((long) d.intValue() != d) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "hour value out of range: " + d);
}
DateTimeValue t = x.dateTime();
try {
return Values.make(new DateTimeValue(t.getZoned().withHour(d.intValue())));
} catch (DateTimeException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, e.getMessage());
}
}
}
// function with_minute(datetime x, long minute) -> datetime
public static final class withMinute implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value x, Value minute) {
if (x == Values.NIL) return Values.NIL;
if (minute == Values.NIL) return Values.NIL;
Long m = minute.longNum();
if ((long) m.intValue() != m) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "minute value out of range: " + m);
}
DateTimeValue t = x.dateTime();
try {
return Values.make(new DateTimeValue(t.getZoned().withMinute(m.intValue())));
} catch (DateTimeException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, e.getMessage());
}
}
}
// function with_second(datetime x, long second) -> datetime
public static final class withSecond implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value x, Value second) {
if (x == Values.NIL) return Values.NIL;
if (second == Values.NIL) return Values.NIL;
Long m = second.longNum();
if ((long) m.intValue() != m) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "second value out of range: " + m);
}
DateTimeValue t = x.dateTime();
try {
return Values.make(new DateTimeValue(t.getZoned().withSecond(m.intValue())));
} catch (DateTimeException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, e.getMessage());
}
}
}
// function with_nano_of_second(datetime x, long second) -> datetime
public static final class withNanoOfSecond implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value x, Value nano_of_second) {
if (x == Values.NIL) return Values.NIL;
if (nano_of_second == Values.NIL) return Values.NIL;
Long n = nano_of_second.longNum();
if ((long) n.intValue() != n) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "nano_of_second value out of range: " + n);
}
DateTimeValue t = x.dateTime();
try {
return Values.make(new DateTimeValue(t.getZoned().withNano(n.intValue())));
} catch (DateTimeException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, e.getMessage());
}
}
}
// (datetime x, string tz) -> datetime
public static final class withTz implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value x, Value tz) {
if (x == Values.NIL) return Values.NIL;
if (tz == Values.NIL) return Values.NIL;
DateTimeValue t = x.dateTime();
String tzId = tz.string();
if (isValidTimeZone(tzId)) {
ZoneId timeZone = ZoneId.of(tzId);
return Values.make(new DateTimeValue(t.getZoned().withZoneSameLocal(timeZone)));
} else {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "unknown time zone id: " + tzId);
}
}
}
// (datetime x, string tz) -> datetime
public static final class sameInstantAtZone implements UserFunction, Arity2UserFunction {
@Override
public Value call(UserCallContext context, Value x, Value tz) {
if (x == Values.NIL) return Values.NIL;
if (tz == Values.NIL) return Values.NIL;
DateTimeValue t = x.dateTime();
String tzId = tz.string();
if (isValidTimeZone(tzId)) {
ZoneId timeZone = ZoneId.of(tzId);
return Values.make(new DateTimeValue(t.getZoned().withZoneSameInstant(timeZone)));
} else {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "unknown time zone id: " + tzId);
}
}
}
// (long year=1970, long month=1, long day_of_month=1, long hour=0, long minute=0, long second=0, long nano_of_second=0, string tz="UTC") -> datetime
public static final class of implements UserFunction, ArityNUserFunction {
@Override
public Value callVariadic(UserCallContext context, Value... args) {
Value year = args[0];
if (year == Values.NIL) return Values.NIL;
Long y = year.longNum();
if ((long) y.intValue() != y) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "year value out of range: " + y);
}
Value month = args[1];
if (month == Values.NIL) return Values.NIL;
Long m = month.longNum();
if ((long) m.intValue() != m) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "month value out of range: " + m);
}
Value day_of_month = args[2];
if (day_of_month == Values.NIL) return Values.NIL;
Long d = day_of_month.longNum();
if ((long) d.intValue() != d) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "day_of_month value out of range: " + d);
}
Value hour = args[3];
if (hour == Values.NIL) return Values.NIL;
Long h = hour.longNum();
if ((long) h.intValue() != h) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "hour value out of range: " + h);
}
Value minute = args[4];
if (minute == Values.NIL) return Values.NIL;
Long mi = minute.longNum();
if ((long) mi.intValue() != mi) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "minute value out of range: " + mi);
}
Value second = args[5];
if (second == Values.NIL) return Values.NIL;
Long s = second.longNum();
if ((long) s.intValue() != s) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "second value out of range: " + s);
}
Value nano_of_second = args[6];
if (nano_of_second == Values.NIL) return Values.NIL;
Long n = nano_of_second.longNum();
if ((long) n.intValue() != n) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "nano_of_second value out of range: " + n);
}
Value tz = args[7];
if (tz == Values.NIL) return Values.NIL;
if (!isValidTimeZone(tz.string())) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, "unknown tz: " + tz);
}
try {
ZonedDateTime zonedDateTime = ZonedDateTime.of(y.intValue(), m.intValue(), d.intValue(), h.intValue(), mi.intValue(), s.intValue(), n.intValue(), ZoneId.of(tz.string()));
return Values.make(new DateTimeValue(zonedDateTime));
} catch (DateTimeException e) {
throw new LangException(LangError.ILLEGAL_ARGUMENT, e.getMessage());
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy