/* * Copyright 2010 NCHOVY * * 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 org.araqne.logstorage; import java.io.IOException; import java.lang.management.ManagementFactory; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import javax.management.MBeanServer; import com.sun.management.HotSpotDiagnosticMXBean; public class DateUtil { private DateUtil() { } public static String getDayText(Date day) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setTimeZone(timeZoneCache); return dateFormat.format(DateUtil.getDay(day)); } private static volatile TimeZone globalValue = TimeZone.getDefault(); private static TimeZone timeZoneCache = TimeZone.getDefault(); public static void setTimeZone(String tz) { timeZoneCache = TimeZone.getTimeZone(tz); dayStarts.clear(); } static ConcurrentHashMap<Long, Date> dayStarts = new ConcurrentHashMap<Long, Date>(); public static Date addDay(Date day, int amount) { if (amount >= 0) { return getDay(new Date(day.getTime() + 86400000L * amount + 43200000L)); } else { return getDay(new Date(day.getTime() + 86400000L * (amount + 1) - 43200000L)); } } public static Date getDay(Date date) { if (date == null) return null; long time = date.getTime(); TimeZone timeZone = timeZoneCache; long dayKey = time - modPos((time + timeZone.getOffset(date.getTime())), 86400000L) + 3600000L * 12; Date dayStart = dayStarts.get(dayKey); if (dayStart != null) return dayStart; else { Calendar c = Calendar.getInstance(timeZoneCache); c.setTime(new Date(dayKey)); c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.MINUTE, 0); c.set(Calendar.SECOND, 0); c.set(Calendar.MILLISECOND, 0); dayStart = c.getTime(); dayStarts.putIfAbsent(dayKey, dayStart); return dayStart; } } private static long modPos(long l, long m) { return ((l % m) + m) % m; } public static List<Date> filt(Collection<Date> dates, Date from, Date to) { List<Date> filtered = new ArrayList<Date>(); // canonicalize Date fromDay = null; Date toDay = null; if (from != null) fromDay = getDay(from); if (to != null) toDay = getDay(to); for (Date day : dates) { day = getDay(day); if (fromDay != null && day.before(fromDay)) continue; if (toDay != null && day.after(toDay)) continue; filtered.add(day); } return filtered; } public static List<Date> sortByDesc(List<Date> dates) { Collections.sort(dates, new Comparator<Date>() { @Override public int compare(Date o1, Date o2) { return (int) (o2.getTime() - o1.getTime()); } }); return dates; } public static Date getDayU(Date date) { long t = date.getTime(); TimeZone timeZone = timeZoneCache; long utcd = t + timeZone.getOffset(t); utcd = utcd - modPos(utcd, 86400000L); long lod = utcd - timeZone.getOffset(utcd); return new Date(lod); } public static void main(String[] args) throws ParseException, IOException { System.out.println(TimeZone.getAvailableIDs().length); perfTest(); // dstTest("Asia/Seoul", "19600503 230000"); // dstTest("America/Argentina/Salta", "19390701 000000"); // testGetDayTextConsistency("Asia/Seoul", "19600514 000000", "19600516 000000"); // DST Start testGetDayTextConsistency("Asia/Seoul", "19600912 000000", "19600914 000000"); // DST End // tests for Southern Hemisphere testGetDayTextConsistency("America/Argentina/Salta", "19391031 000000", "19391102 000000"); // DST Start testGetDayTextConsistency("America/Argentina/Salta", "19400229 000000", "19400302 000000"); // DST End // Korea testGetDayText("Asia/Seoul"); // Japan testGetDayText("JST"); // USA testGetDayText("HAST"); testGetDayText("AKST"); testGetDayText("PST"); testGetDayText("MST"); testGetDayText("CST"); testGetDayText("EST"); testGetDayText("AKDT"); testGetDayText("PDT"); testGetDayText("MDT"); testGetDayText("CDT"); testGetDayText("EDT"); // China testGetDayText("Asia/Shanhai"); testGetDayText("Asia/Harbin"); testGetDayText("Asia/Chongqing"); testGetDayText("Asia/Urumqi"); testGetDayText("Asia/Kashgar"); testGetDayText("Asia/Hong_Kong"); testGetDayText("Asia/Macau"); testGetDayText("Asia/Taipei"); for (String tz : TimeZone.getAvailableIDs()) { if (!testGetDayText(tz)) break; } // fillMemory(); } private static void fillMemory() throws ParseException, IOException { setTimeZone("Asia/Seoul"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); sdf.setTimeZone(timeZoneCache); Date begin = getDay(sdf.parse("1900-01-01")); Date end = getDay(sdf.parse("2101-01-01")); Calendar c = Calendar.getInstance(timeZoneCache); c.setTime(begin); c.set(Calendar.MILLISECOND, 0); while (c.getTime().before(end)) { getDay(c.getTime()); c.add(Calendar.SECOND, 10); if (c.getTime().getTime() % 86400000L == 0) System.out.println(sdf.format(c.getTime())); } MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); HotSpotDiagnosticMXBean bean = ManagementFactory.newPlatformMXBeanProxy(platformMBeanServer, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class); bean.dumpHeap("E:\\w\\araqne\\CalendarDump.hprof", true); } private static void testGetDayTextConsistency(String tzName, String begin, String end) throws ParseException { System.out.println(tzName); setTimeZone(tzName); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss"); sdf.setTimeZone(timeZoneCache); SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd"); sdfd.setTimeZone(timeZoneCache); Date bd = sdf.parse(begin); Date ed = sdf.parse(end); Calendar c = Calendar.getInstance(timeZoneCache); c.setTime(bd); Date prevDay = getDay(c.getTime()); while (c.getTime().before(ed)) { if (!testGetDayText(sdfd, c.getTime())) { System.out.printf("testGetDay failure: %s\n", sdf.format(c.getTime())); break; } if (!prevDay.equals(getDay(c.getTime()))) { System.out.printf( "day changed: %s: %s -> %s\n", sdf.format(c.getTime()), sdf.format(prevDay), sdf.format(getDay(c.getTime()))); } prevDay = getDay(c.getTime()); c.add(Calendar.SECOND, 1); } } private static void dstTest(String tzName, String start) throws ParseException { System.out.println(tzName); setTimeZone(tzName); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss"); sdf.setTimeZone(timeZoneCache); SimpleDateFormat sdfd = new SimpleDateFormat("yyyyMMdd"); sdfd.setTimeZone(timeZoneCache); String dststart = start; Calendar c = Calendar.getInstance(timeZoneCache); c.setTime(sdf.parse(dststart)); System.out.println(c.getTime()); Date prev = c.getTime(); // find DST start while (true) { c.add(Calendar.SECOND, 1); if (!testGetDay(sdfd, c.getTime())) { System.out.printf("getDay test failure: %s but %s\n", sdfd.format(c.getTime()), sdfd.format(getDay(c.getTime()))); } if (c.getTimeZone().inDaylightTime(c.getTime())) break; prev = c.getTime(); } System.out.printf("%s -> getDay(): %s\n", sdf.format(prev), sdf.format(getDay(prev))); System.out.printf( "%s -> getDay(): %s\n", sdf.format(c.getTime()), sdf.format(getDay(c.getTime()))); // find DST end while (true) { c.add(Calendar.SECOND, 1); if (!testGetDay(sdfd, c.getTime())) { System.out.printf("getDay test failure: %s but %s\n", sdfd.format(c.getTime()), sdfd.format(getDay(c.getTime()))); } if (!c.getTimeZone().inDaylightTime(c.getTime())) break; prev = c.getTime(); } System.out.printf("%s -> getDay(): %s\n", sdf.format(prev), sdf.format(getDay(prev))); System.out.printf( "%s -> getDay(): %s\n", sdf.format(c.getTime()), sdf.format(getDay(c.getTime()))); // run testGetDay() 2 day more for (int i = 0; i < 3600 * 2; ++i) { c.add(Calendar.SECOND, 1); if (!testGetDay(sdfd, c.getTime())) { System.out.printf("getDay test failure: %s but %s\n", sdfd.format(c.getTime()), sdfd.format(getDay(c.getTime()))); } prev = c.getTime(); } } private static boolean testGetDay(SimpleDateFormat dateFormat, Date t) { Date d = DateUtil.getDay(t); String td = dateFormat.format(t); String dd = dateFormat.format(d); return td.equals(dd); } private static boolean testGetDayText(SimpleDateFormat dateFormat, Date t) { String dd = DateUtil.getDayText(t); String td = dateFormat.format(t); return td.equals(dd); } private static boolean testGetDayText(String tz) throws ParseException { setTimeZone(tz); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmssz"); SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd"); sdf.setTimeZone(timeZoneCache); sdfd.setTimeZone(timeZoneCache); for (int i = -5; i < 100; ++i) { for (int month = 0; month < 12; ++month) { Calendar c = Calendar.getInstance(timeZoneCache); c.set(2015 - i, month, 1, 12, 0, 1); c.set(Calendar.MILLISECOND, 0); Date t = c.getTime(); String dd = DateUtil.getDayText(t); String td = sdfd.format(t); if (!td.equals(dd)) { System.out.printf("%30s: %s but getDayText(): %s (offset: %d but %d)\n", tz, sdfd.format(t), dd, timeZoneCache.getRawOffset(), timeZoneCache.getOffset(t.getTime())); } } } return true; } private static void perfTest() throws ParseException { long loopCnt = 10000000L; SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss"); Date d1 = sdf.parse("19910627 162735"); long started = MilliTick(); for (int i = 0; i < loopCnt; ++i) { DateUtil.getDay(d1); } System.out.println(MilliTick() - started); // started = MilliTick(); // for (int i = 0; i < loopCnt; ++i) { // Calendar c = Calendar.getInstance(); // c.setTime(d1); // c.set(Calendar.HOUR_OF_DAY, 0); // c.set(Calendar.MINUTE, 0); // c.set(Calendar.SECOND, 0); // c.set(Calendar.MILLISECOND, 0); // c.getTime(); // } // System.out.println(MilliTick() - started); } private static long MilliTick() { return System.nanoTime() / 1000000L; } }