All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.helger.datetime.format.PDTFormatter Maven / Gradle / Ivy

/**
 * Copyright (C) 2014-2016 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * 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 com.helger.datetime.format;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;

import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.PresentForCodeCoverage;
import com.helger.commons.cache.AbstractNotifyingCache;
import com.helger.commons.datetime.DateTimeFormatterCache;
import com.helger.commons.hashcode.HashCodeGenerator;
import com.helger.commons.string.StringHelper;
import com.helger.datetime.EDTType;

/**
 * Create common {@link DateTimeFormatter} objects used for printing and parsing
 * date and time objects.
 *
 * @author Philip Helger
 */
@Immutable
public final class PDTFormatter
{
  /**
   * Internal cache key for {@link LocalizedDateFormatCache}.
   *
   * @author Philip Helger
   */
  @Immutable
  private static final class CacheKey
  {
    private final EDTType m_eDTType;
    private final Locale m_aLocale;
    private final int m_nStyle;

    CacheKey (@Nonnull final EDTType eDTType, @Nullable final Locale aLocale, final int nStyle)
    {
      ValueEnforcer.notNull (eDTType, "DTType");
      ValueEnforcer.isTrue (nStyle == DateFormat.SHORT ||
                            nStyle == DateFormat.MEDIUM ||
                            nStyle == DateFormat.LONG ||
                            nStyle == DateFormat.FULL,
                            "Invalid style provided");
      m_eDTType = eDTType;
      // Ensure a non-null Locale is used - same as in DateFormat itself
      // Having this shortcut here meaning less cache entries that when having
      // "null" as a separate key
      m_aLocale = aLocale != null ? aLocale : Locale.getDefault (Locale.Category.FORMAT);
      m_nStyle = nStyle;
    }

    @Override
    public boolean equals (final Object o)
    {
      if (o == this)
        return true;
      if (o == null || !getClass ().equals (o.getClass ()))
        return false;
      final CacheKey rhs = (CacheKey) o;
      return m_eDTType.equals (rhs.m_eDTType) && m_aLocale.equals (rhs.m_aLocale) && m_nStyle == rhs.m_nStyle;
    }

    @Override
    public int hashCode ()
    {
      return new HashCodeGenerator (this).append (m_eDTType).append (m_aLocale).append (m_nStyle).getHashCode ();
    }
  }

  /**
   * This class caches the compiled patterns for localized date and time
   * formatter. Using e.g.
   * {@link DateTimeFormatter#ofLocalizedDate(java.time.format.FormatStyle)} is
   * not an option because the used "year of era", corresponding to pattern "y"
   * makes problems. Instead "year" with the pattern "u" must be used for best
   * backwards compatibility.
   *
   * @author Philip Helger
   */
  @ThreadSafe
  private static final class LocalizedDateFormatCache extends AbstractNotifyingCache 
  {
    public LocalizedDateFormatCache ()
    {
      super (LocalizedDateFormatCache.class.getName ());
    }

    @Nonnull
    public String getSourcePattern (@Nonnull final CacheKey aKey)
    {
      final DateFormat aDF;
      switch (aKey.m_eDTType)
      {
        case LOCAL_TIME:
          aDF = DateFormat.getTimeInstance (aKey.m_nStyle, aKey.m_aLocale);
          break;
        case LOCAL_DATE:
          aDF = DateFormat.getDateInstance (aKey.m_nStyle, aKey.m_aLocale);
          break;
        default:
          aDF = DateFormat.getDateTimeInstance (aKey.m_nStyle, aKey.m_nStyle, aKey.m_aLocale);
          break;
      }
      return ((SimpleDateFormat) aDF).toPattern ();
    }

    @Override
    protected DateTimeFormatter getValueToCache (@Nonnull final CacheKey aKey)
    {
      String sPattern = getSourcePattern (aKey);
      // Change "year of era" to "year"
      sPattern = StringHelper.replaceAll (sPattern, 'y', 'u');

      // And finally create the cached DateTimeFormatter
      return DateTimeFormatterCache.getDateTimeFormatterStrict (sPattern);
    }
  }

  private static final int DEFAULT_STYLE = DateFormat.DEFAULT;
  private static final LocalizedDateFormatCache s_aCache = new LocalizedDateFormatCache ();

  @PresentForCodeCoverage
  private static final PDTFormatter s_aInstance = new PDTFormatter ();

  private PDTFormatter ()
  {}

  @Nonnull
  public static String getPattern (@Nonnull final EDTType eDTType, @Nullable final Locale aLocale, final int nStyle)
  {
    return s_aCache.getSourcePattern (new CacheKey (eDTType, aLocale, nStyle));
  }

  /**
   * Assign the passed display locale to the passed date time formatter.
   *
   * @param aFormatter
   *        The formatter to be modified. May not be null.
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The modified date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getWithLocale (@Nonnull final DateTimeFormatter aFormatter,
                                                 @Nullable final Locale aDisplayLocale)
  {
    DateTimeFormatter ret = aFormatter;
    if (aDisplayLocale != null)
      ret = ret.withLocale (aDisplayLocale);
    return ret;
  }

  @Nonnull
  private static DateTimeFormatter _getFormatterDate (@Nullable final Locale aDisplayLocale, final int nStyle)
  {
    return getWithLocale (s_aCache.getFromCache (new CacheKey (EDTType.LOCAL_DATE, aDisplayLocale, nStyle)),
                          aDisplayLocale);
  }

  /**
   * Get the default date formatter for the passed locale. This used medium
   * style.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getDefaultFormatterDate (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterDate (aDisplayLocale, DEFAULT_STYLE);
  }

  /**
   * Get the short date formatter for the passed locale.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getShortFormatterDate (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterDate (aDisplayLocale, DateFormat.SHORT);
  }

  /**
   * Get the medium date formatter for the passed locale.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getMediumFormatterDate (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterDate (aDisplayLocale, DateFormat.MEDIUM);
  }

  /**
   * Get the long date formatter for the passed locale.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getLongFormatterDate (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterDate (aDisplayLocale, DateFormat.LONG);
  }

  /**
   * Get the full date formatter for the passed locale.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getFullFormatterDate (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterDate (aDisplayLocale, DateFormat.FULL);
  }

  @Nonnull
  private static DateTimeFormatter _getFormatterTime (@Nullable final Locale aDisplayLocale, final int nStyle)
  {
    return getWithLocale (s_aCache.getFromCache (new CacheKey (EDTType.LOCAL_TIME, aDisplayLocale, nStyle)),
                          aDisplayLocale);
  }

  /**
   * Get the default time formatter for the passed locale. This used medium
   * style.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getDefaultFormatterTime (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterTime (aDisplayLocale, DEFAULT_STYLE);
  }

  /**
   * Get the short time formatter for the passed locale.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getShortFormatterTime (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterTime (aDisplayLocale, DateFormat.SHORT);
  }

  /**
   * Get the medium time formatter for the passed locale.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getMediumFormatterTime (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterTime (aDisplayLocale, DateFormat.MEDIUM);
  }

  /**
   * Get the long time formatter for the passed locale.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getLongFormatterTime (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterTime (aDisplayLocale, DateFormat.LONG);
  }

  /**
   * Get the full time formatter for the passed locale.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getFullFormatterTime (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterTime (aDisplayLocale, DateFormat.FULL);
  }

  @Nonnull
  private static DateTimeFormatter _getFormatterDateTime (@Nullable final Locale aDisplayLocale, final int nStyle)
  {
    return getWithLocale (s_aCache.getFromCache (new CacheKey (EDTType.LOCAL_DATE_TIME, aDisplayLocale, nStyle)),
                          aDisplayLocale);
  }

  /**
   * Get the default date time formatter for the passed locale. The default
   * style is medium.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getDefaultFormatterDateTime (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterDateTime (aDisplayLocale, DEFAULT_STYLE);
  }

  /**
   * Get the short date time formatter for the passed locale.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getShortFormatterDateTime (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterDateTime (aDisplayLocale, DateFormat.SHORT);
  }

  /**
   * Get the medium date time formatter for the passed locale.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getMediumFormatterDateTime (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterDateTime (aDisplayLocale, DateFormat.MEDIUM);
  }

  /**
   * Get the long date time formatter for the passed locale.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getLongFormatterDateTime (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterDateTime (aDisplayLocale, DateFormat.LONG);
  }

  /**
   * Get the full date time formatter for the passed locale.
   *
   * @param aDisplayLocale
   *        The display locale to be used. May be null.
   * @return The created date time formatter. Never null.
   */
  @Nonnull
  public static DateTimeFormatter getFullFormatterDateTime (@Nullable final Locale aDisplayLocale)
  {
    return _getFormatterDateTime (aDisplayLocale, DateFormat.FULL);
  }

  /**
   * Get the {@link DateTimeFormatter} for the given pattern, using our default
   * chronology.
   *
   * @param sPattern
   *        The pattern to be parsed
   * @return The formatter object.
   * @throws IllegalArgumentException
   *         If the pattern is illegal
   */
  @Nonnull
  public static DateTimeFormatter getForPattern (@Nonnull final String sPattern) throws IllegalArgumentException
  {
    return getForPattern (sPattern, null);
  }

  /**
   * Get the STRICT {@link DateTimeFormatter} for the given pattern and locale,
   * using our default chronology.
   *
   * @param sPattern
   *        The pattern to be parsed
   * @param aDisplayLocale
   *        The locale to be used. May be null.
   * @return The formatter object.
   * @throws IllegalArgumentException
   *         If the pattern is illegal
   */
  @Nonnull
  public static DateTimeFormatter getForPattern (@Nonnull final String sPattern,
                                                 @Nullable final Locale aDisplayLocale) throws IllegalArgumentException
  {
    final DateTimeFormatter aDTF = DateTimeFormatterCache.getDateTimeFormatterStrict (sPattern);
    return getWithLocale (aDTF, aDisplayLocale);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy