001package com.box.sdk; 002 003import java.text.DateFormat; 004import java.text.ParseException; 005import java.text.SimpleDateFormat; 006import java.time.Instant; 007import java.util.Date; 008import java.util.TimeZone; 009 010/** 011 * Contains methods for parsing and formatting dates for use with the Box API. 012 */ 013public final class BoxDateFormat { 014 private static final ThreadLocal<DateFormat> THREAD_LOCAL_DATE_FORMAT_SECONDS = ThreadLocal.withInitial(() -> { 015 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX"); 016 sdf.setTimeZone(TimeZone.getTimeZone("UTC")); 017 return sdf; 018 }); 019 020 private static final ThreadLocal<DateFormat> THREAD_LOCAL_DATE_FORMAT_MILLISECONDS = ThreadLocal.withInitial(() -> { 021 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX"); 022 sdf.setTimeZone(TimeZone.getTimeZone("UTC")); 023 return sdf; 024 }); 025 026 private static final ThreadLocal<DateFormat> THREAD_LOCAL_DATE_ONLY = ThreadLocal.withInitial(() -> { 027 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 028 sdf.setTimeZone(TimeZone.getTimeZone("UTC")); 029 return sdf; 030 }); 031 032 private BoxDateFormat() { 033 } 034 035 /** 036 * Parses a date string returned by the Box API into a {@link Date} object. 037 * 038 * @param dateString a string containing the date. 039 * @return the parsed date. 040 * @throws ParseException if the string cannot be parsed into a valid date. 041 */ 042 public static Date parse(String dateString) throws ParseException { 043 try { 044 return THREAD_LOCAL_DATE_FORMAT_SECONDS.get().parse(dateString); 045 } catch (ParseException pe) { 046 return THREAD_LOCAL_DATE_FORMAT_MILLISECONDS.get().parse(dateString); 047 } 048 } 049 050 /** 051 * Parses a date in format of yyyy-MM-dd. 052 * 053 * @param date date to parse. 054 * @return parsed date. 055 * @throws ParseException if the string cannot be parsed into a valid date. 056 */ 057 public static Date parseDateOnly(String date) throws ParseException { 058 return THREAD_LOCAL_DATE_ONLY.get().parse(date); 059 } 060 061 /** 062 * Formats a date as a string that can be sent to the Box API. 063 * 064 * @param date the date to format. 065 * @return a string containing the formatted date. 066 */ 067 public static String format(Date date) { 068 return THREAD_LOCAL_DATE_FORMAT_SECONDS.get().format(date); 069 } 070 071 /** 072 * Formats an Instant as a string that can be sent to the Box API. 073 * 074 * @param instant the instant to format. 075 * @return a string containing the formatted instant. 076 */ 077 public static String format(Instant instant) { 078 return THREAD_LOCAL_DATE_FORMAT_SECONDS.get().format(Date.from(instant)); 079 } 080 081 /** 082 * Formats a date as a string yyyy-MM-dd that can be sent to the Box API. 083 * 084 * @param date the date to format. 085 * @return a yyyy-MM-dd string containing the formatted date. 086 */ 087 public static String formatAsDateOnly(Date date) { 088 return THREAD_LOCAL_DATE_ONLY.get().format(date); 089 } 090}