content: /*
   * Latke - 一款以 JSON 为主的 Java Web 框架
   * Copyright (c) 2009-present, b3log.org
   *
   * Latke is licensed under Mulan PSL v2.
   * You can use this software according to the terms and conditions of the Mulan PSL v2.
   * You may obtain a copy of Mulan PSL v2 at:
   *         http://license.coscl.org.cn/MulanPSL2
   * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
   * See the Mulan PSL v2 for more details.
   */
  package org.b3log.latke.util;
  
  import org.b3log.latke.ioc.BeanManager;
  import org.b3log.latke.service.LangPropsService;
  
  import java.util.Calendar;
  import java.util.Date;
  import java.util.Locale;
  import java.util.Map;
  
  /**
   * Time utilities.
   *
   * @author <a href="http://88250.b3log.org">Liang Ding</a>
   * @version 1.0.1.2, Jun 10, 2023
   * @since 2.4.4
   */
  public final class Times {
  
      /**
       * Minute unit.
       */
      private static final long MINUTE_UNIT = 60 * 1000L;
  
      /**
       * Hour unit.
       */
      private static final long HOUR_UNIT = 60 * MINUTE_UNIT;
  
      /**
       * Day unit.
       */
      private static final long DAY_UNIT = 24 * HOUR_UNIT;
  
      /**
       * Week unit.
       */
      private static final long WEEK_UNIT = 7 * DAY_UNIT;
  
      /**
       * Month unit.
       */
      private static final long MONTH_UNIT = 31 * DAY_UNIT;
  
      /**
       * Year unit.
       */
      private static final long YEAR_UNIT = 12 * MONTH_UNIT;
  
      /**
       * Gets time ago format text with default locale.
       *
       * @param time the specified time.
       * @return time ago format text
       */
      public static String getTimeAgo(final long time) {
          final Locale locale = Locales.getLocale();
          return getTimeAgo(time, locale);
      }
  
      /**
       * Gets time ago format text.
       *
       * @param time   the specified time.
       * @param locale the specified locale
       * @return time ago format text
       */
      public static String getTimeAgo(final long time, final Locale locale) {
          final BeanManager beanManager = BeanManager.getInstance();
          final LangPropsService langService = beanManager.getReference(LangPropsService.class);
          final Map<String, String> langs = langService.getAll(locale);
  
          final long diff = System.currentTimeMillis() - time;
          long r;
  
          String label;
          if (diff > YEAR_UNIT) {
              r = diff / YEAR_UNIT;
              if (1 == r) {
                  label = langs.get("yearAgoLabel");
              } else {
                  label = langs.get("yearsAgoLabel");
              }
              return r + " " + label;
          }
  
          if (diff > MONTH_UNIT) {
              r = diff / MONTH_UNIT;
              if (1 == r) {
                  label = langs.get("monthAgoLabel");
              } else {
                  label = langs.get("monthsAgoLabel");
              }
              return r + " " + label;
          }
  
          if (diff > WEEK_UNIT) {
              r = diff / WEEK_UNIT;
              if (1 == r) {
                  label = langs.get("weekAgoLabel");
              } else {
                  label = langs.get("weeksAgoLabel");
              }
              return r + " " + label;
          }
  
          if (diff > DAY_UNIT) {
              r = diff / DAY_UNIT;
              if (1 == r) {
                  label = langs.get("dayAgoLabel");
              } else {
                  label = langs.get("daysAgoLabel");
              }
              return r + " " + label;
          }
  
          if (diff > HOUR_UNIT) {
              r = diff / HOUR_UNIT;
              if (1 == r) {
                  label = langs.get("hourAgoLabel");
              } else {
                  label = langs.get("hoursAgoLabel");
              }
              return r + " " + label;
          }
  
          if (diff > MINUTE_UNIT) {
              r = diff / MINUTE_UNIT;
              if (1 == r) {
                  label = langs.get("minuteAgoLabel");
              } else {
                  label = langs.get("minutesAgoLabel");
              }
              return r + " " + label;
          }
          return langs.get("justNowLabel");
      }
  
      /**
       * Determines whether the specified date1 is the same day with the specified date2.
       *
       * @param date1 the specified date1
       * @param date2 the specified date2
       * @return {@code true} if it is the same day, returns {@code false} otherwise
       */
      public static boolean isSameDay(final Date date1, final Date date2) {
          final Calendar cal1 = Calendar.getInstance();
          cal1.setTime(date1);
          final Calendar cal2 = Calendar.getInstance();
          cal2.setTime(date2);
          return cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA)
                  && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)
                  && cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH)
                  && cal1.get(Calendar.DATE) == cal2.get(Calendar.DATE);
      }
  
      /**
       * Determines whether the specified date1 is the same week with the specified date2.
       *
       * @param date1 the specified date1
       * @param date2 the specified date2
       * @return {@code true} if it is the same week, returns {@code false} otherwise
       */
      public static boolean isSameWeek(final Date date1, final Date date2) {
          final Calendar cal1 = Calendar.getInstance();
          cal1.setFirstDayOfWeek(Calendar.MONDAY);
          cal1.setTime(date1);
          final Calendar cal2 = Calendar.getInstance();
          cal2.setFirstDayOfWeek(Calendar.MONDAY);
          cal2.setTime(date2);
          return cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA)
                  && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)
                  && cal1.get(Calendar.WEEK_OF_YEAR) == cal2.get(Calendar.WEEK_OF_YEAR);
      }
  
      /**
       * Determines whether the specified date1 is the same month with the specified date2.
       *
       * @param date1 the specified date1
       * @param date2 the specified date2
       * @return {@code true} if it is the same month, returns {@code false} otherwise
       */
      public static boolean isSameMonth(final Date date1, final Date date2) {
          final Calendar cal1 = Calendar.getInstance();
          cal1.setTime(date1);
          final Calendar cal2 = Calendar.getInstance();
          cal2.setTime(date2);
          return cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA)
                  && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)
                  && cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH);
      }
  
      /**
       * Gets the day start time with the specified time.
       *
       * @param time the specified time
       * @return day start time
       */
      public static long getDayStartTime(final long time) {
          final Calendar start = Calendar.getInstance();
          start.setTimeInMillis(time);
          final int year = start.get(Calendar.YEAR);
          final int month = start.get(Calendar.MONTH);
          final int day = start.get(Calendar.DATE);
          start.set(year, month, day, 0, 0, 0);
          start.set(Calendar.MILLISECOND, 0);
          return start.getTimeInMillis();
      }
  
      /**
       * Gets the day end time with the specified time.
       *
       * @param time the specified time
       * @return day end time
       */
      public static long getDayEndTime(final long time) {
          final Calendar end = Calendar.getInstance();
          end.setTimeInMillis(time);
          final int year = end.get(Calendar.YEAR);
          final int month = end.get(Calendar.MONTH);
          final int day = end.get(Calendar.DATE);
          end.set(year, month, day, 23, 59, 59);
          end.set(Calendar.MILLISECOND, 999);
          return end.getTimeInMillis();
      }
  
      /**
       * Gets the week day with the specified time.
       *
       * @param time the specified time
       * @return week day
       */
      public static int getWeekDay(final long time) {
          final Calendar calendar = Calendar.getInstance();
          calendar.setTimeInMillis(time);
          int ret = calendar.get(Calendar.DAY_OF_WEEK) - 1;
          if (ret <= 0) {
              ret = 7;
          }
          return ret;
      }
  
      /**
       * Gets the week start time with the specified time.
       *
       * @param time the specified time
       * @return week start time
       */
      public static long getWeekStartTime(final long time) {
          final Calendar start = Calendar.getInstance();
          start.setFirstDayOfWeek(Calendar.MONDAY);
          start.setTimeInMillis(time);
          start.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
          start.set(Calendar.HOUR, 0);
          start.set(Calendar.MINUTE, 0);
          start.set(Calendar.SECOND, 0);
          start.set(Calendar.MILLISECOND, 0);
          return start.getTimeInMillis();
      }
  
      /**
       * Gets the week end time with the specified time.
       *
       * @param time the specified time
       * @return week end time
       */
      public static long getWeekEndTime(final long time) {
          final Calendar end = Calendar.getInstance();
          end.setFirstDayOfWeek(Calendar.MONDAY);
          end.setTimeInMillis(time);
          end.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
          end.set(Calendar.HOUR, 23);
          end.set(Calendar.MINUTE, 59);
          end.set(Calendar.SECOND, 59);
          end.set(Calendar.MILLISECOND, 999);
          return end.getTimeInMillis();
      }
  
      /**
       * Gets the month start time with the specified time.
       *
       * @param time the specified time
       * @return month start time
       */
      public static long getMonthStartTime(final long time) {
          final Calendar start = Calendar.getInstance();
          start.setTimeInMillis(time);
          final int year = start.get(Calendar.YEAR);
          final int month = start.get(Calendar.MONTH);
          start.set(year, month, 1, 0, 0, 0);
          start.set(Calendar.MILLISECOND, 0);
          return start.getTimeInMillis();
      }
  
      /**
       * Gets the month end time with the specified time.
       *
       * @param time the specified time
       * @return month end time
       */
      public static long getMonthEndTime(final long time) {
          final Calendar end = Calendar.getInstance();
          end.setTimeInMillis(getDayStartTime(time));
          end.set(Calendar.DAY_OF_MONTH, end.getActualMaximum(Calendar.DAY_OF_MONTH));
          end.set(Calendar.HOUR, 23);
          end.set(Calendar.MINUTE, 59);
          end.set(Calendar.SECOND, 59);
          end.set(Calendar.MILLISECOND, 999);
          return end.getTimeInMillis();
      }
  
      /**
       * Private constructor.
       */
      private Times() {
      }
  }
  