Line data Source code
1 : // Copyright 2008 Google Inc. 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.json; 16 : 17 : import com.google.common.base.Splitter; 18 : import java.sql.Timestamp; 19 : import java.util.Calendar; 20 : import java.util.List; 21 : import java.util.TimeZone; 22 : 23 : /** Utility to parse Timestamp from a string. */ 24 : public class JavaSqlTimestampHelper { 25 : 26 13 : private static final Splitter TIMESTAMP_SPLITTER = Splitter.on(" "); 27 13 : private static final Splitter DATE_SPLITTER = Splitter.on("-"); 28 13 : private static final Splitter TIME_SPLITTER = Splitter.on(":"); 29 : 30 : /** 31 : * Parse a string into a timestamp. 32 : * 33 : * <p>Note that {@link Timestamp}s have no timezone, so the result is relative to the UTC epoch. 34 : * 35 : * <p>Supports the format {@code yyyy-MM-dd[ HH:mm:ss[.SSS][ Z]]} where {@code Z} is a 4-digit 36 : * offset with sign, e.g. {@code -0500}. 37 : * 38 : * @param s input string. 39 : * @return resulting timestamp. 40 : */ 41 : public static Timestamp parseTimestamp(String s) { 42 13 : List<String> components = TIMESTAMP_SPLITTER.splitToList(s); 43 13 : if (components.size() < 1 || components.size() > 3) { 44 0 : throw new IllegalArgumentException("Expected date and optional time: " + s); 45 : } 46 13 : String date = components.get(0); 47 13 : String time = components.size() >= 2 ? components.get(1) : null; 48 13 : int off = components.size() == 3 ? parseTimeZone(components.get(2)) : 0; 49 13 : List<String> dSplit = DATE_SPLITTER.splitToList(date); 50 13 : if (dSplit.size() != 3) { 51 1 : throw new IllegalArgumentException("Invalid date format: " + date); 52 : } 53 : int yy, mm, dd; 54 : try { 55 13 : yy = Integer.parseInt(dSplit.get(0)); 56 13 : mm = Integer.parseInt(dSplit.get(1)) - 1; 57 13 : dd = Integer.parseInt(dSplit.get(2)); 58 1 : } catch (NumberFormatException e) { 59 1 : throw new IllegalArgumentException("Invalid date format: " + date, e); 60 13 : } 61 : 62 : int hh, mi, ss, ns; 63 13 : if (time != null) { 64 13 : int p = time.indexOf('.'); 65 : String t; 66 : double f; 67 : try { 68 13 : if (p >= 0) { 69 9 : t = time.substring(0, p); 70 9 : f = Double.parseDouble("0." + time.substring(p + 1)); 71 : } else { 72 5 : t = time; 73 5 : f = 0; 74 : } 75 13 : List<String> tSplit = TIME_SPLITTER.splitToList(t); 76 13 : if (tSplit.size() != 3) { 77 0 : throw new IllegalArgumentException("Invalid time format: " + time); 78 : } 79 13 : hh = Integer.parseInt(tSplit.get(0)); 80 13 : mi = Integer.parseInt(tSplit.get(1)); 81 13 : ss = Integer.parseInt(tSplit.get(2)); 82 13 : ns = (int) Math.round(f * 1e9); 83 0 : } catch (NumberFormatException e) { 84 0 : throw new IllegalArgumentException("Invalid time format: " + time, e); 85 13 : } 86 13 : } else { 87 5 : hh = 0; 88 5 : mi = 0; 89 5 : ss = 0; 90 5 : ns = 0; 91 : } 92 13 : Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); 93 13 : calendar.set(yy, mm, dd, hh, mi, ss); 94 13 : Timestamp result = new Timestamp(calendar.toInstant().toEpochMilli() - off); 95 13 : result.setNanos(ns); 96 13 : return result; 97 : } 98 : 99 : private static int parseTimeZone(String s) { 100 5 : if (s.length() != 5 || (s.charAt(0) != '-' && s.charAt(0) != '+')) { 101 0 : throw new IllegalArgumentException("Invalid time zone: " + s); 102 : } 103 5 : for (int i = 1; i < s.length(); i++) { 104 5 : if (s.charAt(i) < '0' || s.charAt(i) > '9') { 105 0 : throw new IllegalArgumentException("Invalid time zone: " + s); 106 : } 107 : } 108 : int off = 109 5 : (s.charAt(0) == '-' ? -1 : 1) 110 : * 60 111 : * 1000 112 5 : * ((60 * Integer.parseInt(s.substring(1, 3))) + Integer.parseInt(s.substring(3, 5))); 113 5 : return off; 114 : } 115 : 116 : private JavaSqlTimestampHelper() {} 117 : }