/* * Microsoft JDBC Driver for SQL Server * * Copyright(c) Microsoft Corporation All rights reserved. * * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework.sqlType; import java.sql.JDBCType; import java.sql.Timestamp; import java.util.Calendar; import java.util.concurrent.ThreadLocalRandom; import microsoft.sql.DateTimeOffset; public class SqlDateTimeOffset extends SqlDateTime { public static boolean returnMinMax = (0 == ThreadLocalRandom.current().nextInt(5)); // 20% chance of return Min/Max value private static String numberCharSet2 = "123456789"; DateTimeOffset maxDTS; DateTimeOffset minDTS; long max; long min; // TODO: datetiemoffset can extend SqlDateTime2 // timezone is not supported in Timestamp so its useless to initialize // min/max with offset public SqlDateTimeOffset() { super("datetimeoffset", JDBCType.TIMESTAMP /* microsoft.sql.Types.DATETIMEOFFSET */, null, null); type = microsoft.sql.DateTimeOffset.class; minvalue = Timestamp.valueOf((String) SqlTypeValue.DATETIMEOFFSET.minValue); maxvalue = Timestamp.valueOf((String) SqlTypeValue.DATETIMEOFFSET.maxValue); this.precision = 7; this.variableLengthType = VariableLengthType.Precision; generatePrecision(); maxDTS = calculateDateTimeOffsetMinMax("max", precision, (String) SqlTypeValue.DATETIMEOFFSET.maxValue); minDTS = calculateDateTimeOffsetMinMax("min", precision, (String) SqlTypeValue.DATETIMEOFFSET.minValue); max = maxDTS.getTimestamp().getTime(); min = minDTS.getTimestamp().getTime(); } /** * create data */ public Object createdata() { return generateDatetimeoffset(this.precision); } /** * * @param precision * @return */ public Object generateDatetimeoffset(Integer precision) { if (null == precision) { precision = 7; } Timestamp ts = generateTimestamp(max, min); if (null == ts) { return null; } if (returnMinMax) { if (ThreadLocalRandom.current().nextBoolean()) { return maxDTS; } else { return minDTS; } } int precisionDigits = buildPrecision(precision, numberCharSet2); ts.setNanos(precisionDigits); int randomTimeZoneInMinutes = ThreadLocalRandom.current().nextInt(1681) - 840; return microsoft.sql.DateTimeOffset.valueOf(ts, randomTimeZoneInMinutes); } private static DateTimeOffset calculateDateTimeOffsetMinMax(String maxOrMin, Integer precision, String tsMinMax) { int providedTimeZoneInMinutes; if (maxOrMin.toLowerCase().equals("max")) { providedTimeZoneInMinutes = 840; } else { providedTimeZoneInMinutes = -840; } Timestamp tsMax = Timestamp.valueOf(tsMinMax); Calendar cal = Calendar.getInstance(); long offset = cal.get(Calendar.ZONE_OFFSET); // in milliseconds // max Timestamp + difference of current time zone and GMT - provided time zone in milliseconds tsMax = new Timestamp(tsMax.getTime() + offset - (providedTimeZoneInMinutes * 60 * 1000)); if (maxOrMin.toLowerCase().equals("max")) { int precisionDigits = buildPrecision(precision, "9"); tsMax.setNanos(precisionDigits); } return microsoft.sql.DateTimeOffset.valueOf(tsMax, providedTimeZoneInMinutes); } private static int buildPrecision(int precision, String charSet) { String stringValue = calculatePrecisionDigits(precision, charSet); return Integer.parseInt(stringValue); } // setNanos(999999900) gives 00:00:00.9999999 // so, this value has to be 9 digits private static String calculatePrecisionDigits(int precision, String charSet) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < precision; i++) { char c = pickRandomChar(charSet); sb.append(c); } for (int i = sb.length(); i < 9; i++) { sb.append("0"); } return sb.toString(); } private static Timestamp generateTimestamp(long max, long min) { if (returnMinMax) { if (ThreadLocalRandom.current().nextBoolean()) { return new Timestamp(max); } else { return new Timestamp(min); } } while (true) { long longValue = ThreadLocalRandom.current().nextLong(); if (longValue >= min && longValue <= max) { return new Timestamp(longValue); } } } private static char pickRandomChar(String charSet) { int charSetLength = charSet.length(); int randomIndex = ThreadLocalRandom.current().nextInt(charSetLength); return charSet.charAt(randomIndex); } }