Форматирование милли/микро/нано секунд в java.sql.Timestamp

от автора

В JVM 1.8 отсутствует удобный и простой в использовании класс форматирования класса java.sql.Timestamp с микро и нано секундами. Есть специализированный пакет java.time с достаточно разнообразной функциональностью. Но его использование для преобразования типа java.sql.Timestamp в строку и из строки в тип выглядит как то сложновато. Хотелось иметь простой способ преобразования с функциональностью класса java.text.SimpleDateFormat.

Конечно есть множество советов и вариантов решения этих преобразований в интернет, но все они меня как то не устроили по разным причинам. Повозившись и помучавшись с поиском решения решил написать свой класс, при этом реализовывать весь разбор строки и форматирование в строку совсем не хотелось. Решил наследовать свой класс от одного из существующих классов, переопределив поведение только интересуемой меня функциональности. Но и здесь меня ждало большое разочарование из-за ограничения зон видимости полей, методов и используемых классов в классах, от которых я пробовал наследоваться. .

Хочешь, не хочешь, но надо все же писать полностью свой класс, но писать то все с нуля не хочется. И тут мне в голову пришла идея, раз нельзя наследоваться от класса java.text.SimpleDateFormat, но использовать то его можно же. Идея реализации простая, форматировать и разбирать милли/микро/нано секунды отдельно. Сказано, сделано.

package ru.funsys.util;  import java.sql.Timestamp; import java.text.MessageFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Locale;  /**  * Класс форматирования класса Timestamp c милли/микро/нано секундами  *   * @author Валерий Лиховских  *  */ public class TimestampFormatter {   /**  * строка форматирования даты и времени. Формируется из исходной строки шаблона форматирования  */ private String format;   /**  * строка форматирования, используемая для парсинга. Формируется из исходной строки шаблона форматирования  */ private String parse;   /**  * местоположения в строке шаблона форматирования милли/микро/нано секунд. Формируется из исходной строки шаблона форматирования  */ private int first;  /**  * разрядность после запятой милли/микро/нано секунд, вычисляется по строке шаблона форматирования  */ private int size;  /**  * Объект локализации   */ private Locale locale;      /**      * строка шаблона форматирования по умолчанию      */     public static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX"; //$NON-NLS-1$      /**      * символ шаблона форматирования милли/микро/нано секунд      */     public static final char CHAR_S = 'S'; //$NON-NLS-1$      public TimestampFormatter() { this(DEFAULT_DATETIME_PATTERN, Locale.getDefault()); }  /**  * @param pattern строка шаблона форматирования по умолчанию  */ public TimestampFormatter(String pattern) { this(pattern, Locale.getDefault()); }  /**  * @param pattern строка шаблона форматирования по умолчанию  * @param locale объект локализации  */ public TimestampFormatter(String pattern, Locale locale) { first = pattern.indexOf(CHAR_S); if (first != -1) { String datetime = pattern.substring(0, first); int last = pattern.lastIndexOf(CHAR_S) + 1; if (last > 0 && last < pattern.length()) { format = datetime + "'{0}'" + pattern.substring(last); // {0} - для милли/микро/нано секунд parse = datetime + pattern.substring(last); size = last - first; } else { format = datetime + "'{0}'"; // {0} - для милли/микро/нано секунд parse = datetime; size = pattern.length() - first; } } else { this.format = pattern; this.parse = pattern; size = 0; } this.locale = locale;  }  /**  * Форматировать Timestamp  *    * @param timestamp значение форматирования  *   * @return строковое представление Timestamp   */ public String format(Timestamp timestamp) { String nanos; if (size == 0) nanos = ""; else nanos = Integer.toString(timestamp.getNanos() + 1000000000).substring(1, 1 + size); return MessageFormat.format(new SimpleDateFormat(format, locale).format(timestamp), nanos); }  /**  * Парсить строковое представление Timestamp  *    * @param source строка парсиyга  *   * @return результат преобразования в Timestamp  *   * @throws ParseException ошибка форматирования  */ public Timestamp parse(String source) throws ParseException { int tmpFirst; if (source.indexOf('T') > 0) tmpFirst = first - 2; else tmpFirst = first; StringBuffer tmpSource = new StringBuffer().append(source.substring(0, tmpFirst)); if (size > 0) { tmpSource.append(source.substring(tmpFirst + size)); } Timestamp timestamp = new Timestamp(new SimpleDateFormat(parse, locale).parse(tmpSource.toString()).getTime()); if (size > 0) { int tmpNamo = Integer.parseInt(source.substring(tmpFirst, tmpFirst + size)); for (int index = size; index < 9; index++) { tmpNamo = tmpNamo * 10; } timestamp.setNanos(tmpNamo); } return timestamp; }  } 

В результате получился компактный класс по своей функциональности сопоставим с классом java.text.SimpleDateFormat. И самое главное, простой в использовании.

public static void main(String[] args) { Timestamp t = new Timestamp(System.currentTimeMillis()); t.setNanos(345012000); // устанавливать наносекунды TimestampFormatter f = new TimestampFormatter(); String s = f.format(t); System.out.println(s); try {             // обратное преобразование для проверки Timestamp n = f.parse(s); System.out.println(f.format(n)); } catch (Exception e) { e.printStackTrace(); } }

Результат

2022-11-18T09:20:35.345012+03:00 2022-11-18T09:20:35.345012+03:00

Дальнейшее использование этого класса в любых потребностей, думаю, затруднение не вызовет.


ссылка на оригинал статьи https://habr.com/ru/post/700148/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *