HarmonyOS鸿蒙Next中类似于swiftDate的日期时间操作库

HarmonyOS鸿蒙Next中类似于swiftDate的日期时间操作库 之前在iOS开发中,有一款三方库 swiftDate,挺好用,如何实现一个类似的库

3 回复

SwiftDate 可以自动识别所有主流的日期时间格式(ISO8601、RSS、Alt RSS、.NET、SQL、HTTP 等),您也可以提供自定义格式

// All default datetime formats (15+) are recognized automatically
let _ = "2010-05-20 15:30:00".toDate()
// You can also provide your own format!
let _ = "2010-05-20 15:30".toDate("yyyy-MM-dd HH:mm")
// All ISO8601 variants are supported too with timezone parsing!
let _ = "2017-09-17T11:59:29+02:00".toISODate()
// RSS, Extended, HTTP, SQL, .NET and all the major variants are supported!
let _ = "19 Nov 2015 22:20:40 +0100".toRSS(alt: true)

按照SwiftDate 进行一些常用日期时间工具类实现

/**
 * 日期时间工具类
 * 类似 SwiftDate 的功能实现
 */

export interface DateComponents {
  year: number;
  month: number;
  day: number;
  hour: number;
  minute: number;
  second: number;
  millisecond: number;
  weekday?: number; // 1-7, 1=Sunday
}

export interface DateRange {
  start: Date;
  end: Date;
}

export class DateUtils {
  /**
   * 日期格式化
   * [@param](/user/param) date 日期对象
   * [@param](/user/param) format 格式化字符串
   * [@returns](/user/returns) 格式化后的字符串
   * 
   * 格式说明:
   * yyyy - 4位年份
   * MM - 2位月份 (01-12)
   * dd - 2位日期 (01-31)
   * HH - 24小时制小时 (00-23)
   * mm - 分钟 (00-59)
   * ss - 秒 (00-59)
   * EEE - 星期几 (Mon, Tue, ...)
   * EEEE - 完整星期 (Monday, Tuesday, ...)
   */
  static format(date: Date, format: string): string {
    const year = date.getFullYear();
    const month = date.getMonth() + 1;
    const day = date.getDate();
    const hour = date.getHours();
    const minute = date.getMinutes();
    const second = date.getSeconds();
    const weekday = date.getDay();

    const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
    const weekdaysShort = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

    let result = format;
    result = result.replace(/yyyy/g, year.toString());
    result = result.replace(/MM/g, this.padZero(month));
    result = result.replace(/dd/g, this.padZero(day));
    result = result.replace(/HH/g, this.padZero(hour));
    result = result.replace(/mm/g, this.padZero(minute));
    result = result.replace(/ss/g, this.padZero(second));
    result = result.replace(/EEEE/g, weekdays[weekday]);
    result = result.replace(/EEE/g, weekdaysShort[weekday]);

    return result;
  }

  /**
   * 解析日期字符串
   * [@param](/user/param) dateString 日期字符串
   * [@param](/user/param) format 日期格式(可选)
   * [@returns](/user/returns) Date对象
   */
  static parse(dateString: string, format?: string): Date | null {
    if (format) {
      // 简单解析,支持常见格式
      return this.parseWithFormat(dateString, format);
    }
    // 尝试标准格式
    const date = new Date(dateString);
    return isNaN(date.getTime()) ? null : date;
  }

  /**
   * 根据格式解析日期
   */
  private static parseWithFormat(dateString: string, format: string): Date | null {
    // 简化实现,支持 yyyy-MM-dd 和 yyyy-MM-dd HH:mm:ss
    const ymdMatch = dateString.match(/(\d{4})-(\d{2})-(\d{2})/);
    if (ymdMatch) {
      const year = parseInt(ymdMatch[1]);
      const month = parseInt(ymdMatch[2]) - 1;
      const day = parseInt(ymdMatch[3]);
      
      const hmsMatch = dateString.match(/(\d{2}):(\d{2}):(\d{2})/);
      if (hmsMatch) {
        const hour = parseInt(hmsMatch[1]);
        const minute = parseInt(hmsMatch[2]);
        const second = parseInt(hmsMatch[3]);
        return new Date(year, month, day, hour, minute, second);
      }
      return new Date(year, month, day);
    }
    return null;
  }

  /**
   * 获取日期组件
   */
  static getComponents(date: Date): DateComponents {
    return {
      year: date.getFullYear(),
      month: date.getMonth() + 1,
      day: date.getDate(),
      hour: date.getHours(),
      minute: date.getMinutes(),
      second: date.getSeconds(),
      millisecond: date.getMilliseconds(),
      weekday: date.getDay() + 1 // 1-7, 1=Sunday
    };
  }

  /**
   * 从组件创建日期
   */
  static fromComponents(components: DateComponents): Date {
    return new Date(
      components.year,
      components.month - 1,
      components.day,
      components.hour || 0,
      components.minute || 0,
      components.second || 0,
      components.millisecond || 0
    );
  }

  /**
   * 日期加法
   */
  static add(date: Date, unit: 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second', value: number): Date {
    const newDate = new Date(date);
    switch (unit) {
      case 'year':
        newDate.setFullYear(newDate.getFullYear() + value);
        break;
      case 'month':
        newDate.setMonth(newDate.getMonth() + value);
        break;
      case 'day':
        newDate.setDate(newDate.getDate() + value);
        break;
      case 'hour':
        newDate.setHours(newDate.getHours() + value);
        break;
      case 'minute':
        newDate.setMinutes(newDate.getMinutes() + value);
        break;
      case 'second':
        newDate.setSeconds(newDate.getSeconds() + value);
        break;
    }
    return newDate;
  }

  /**
   * 日期减法
   */
  static subtract(date: Date, unit: 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second', value: number): Date {
    return this.add(date, unit, -value);
  }

  /**
   * 计算两个日期之间的差值
   */
  static diff(start: Date, end: Date, unit: 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond'): number {
    const diffMs = end.getTime() - start.getTime();
    switch (unit) {
      case 'millisecond':
        return diffMs;
      case 'second':
        return Math.floor(diffMs / 1000);
      case 'minute':
        return Math.floor(diffMs / (1000 * 60));
      case 'hour':
        return Math.floor(diffMs / (1000 * 60 * 60));
      case 'day':
        return Math.floor(diffMs / (1000 * 60 * 60 * 24));
      case 'month':
        return (end.getFullYear() - start.getFullYear()) * 12 + (end.getMonth() - start.getMonth());
      case 'year':
        return end.getFullYear() - start.getFullYear();
      default:
        return diffMs;
    }
  }

  /**
   * 相对时间描述(如"2小时前")
   */
  static timeAgo(date: Date, now: Date = new Date()): string {
    const diffSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
    
    if (diffSeconds < 0) {
      return this.timeUntil(date, now);
    }

    if (diffSeconds < 60) {
      return diffSeconds <= 1 ? '刚刚' : `${diffSeconds}秒前`;
    }

    const diffMinutes = Math.floor(diffSeconds / 60);
    if (diffMinutes < 60) {
      return `${diffMinutes}分钟前`;
    }

    const diffHours = Math.floor(diffMinutes / 60);
    if (diffHours < 24) {
      return `${diffHours}小时前`;
    }

    const diffDays = Math.floor(diffHours / 24);
    if (diffDays < 7) {
      return `${diffDays}天前`;
    }

    const diffWeeks = Math.floor(diffDays / 7);
    if (diffWeeks < 4) {
      return `${diffWeeks}周前`;
    }

    const diffMonths = Math.floor(diffDays / 30);
    if (diffMonths < 12) {
      return `${diffMonths}个月前`;
    }

    const diffYears = Math.floor(diffDays / 365);
    return `${diffYears}年前`;
  }

  /**
   * 未来时间描述(如"2小时后")
   */
  static timeUntil(date: Date, now: Date = new Date()): string {
    const diffSeconds = Math.floor((date.getTime() - now.getTime()) / 1000);
    
    if (diffSeconds < 0) {
      return this.timeAgo(date, now);
    }

    if (diffSeconds < 60) {
      return diffSeconds <= 1 ? '即将' : `${diffSeconds}秒后`;
    }

    const diffMinutes = Math.floor(diffSeconds / 60);
    if (diffMinutes < 60) {
      return `${diffMinutes}分钟后`;
    }

    const diffHours = Math.floor(diffMinutes / 60);
    if (diffHours < 24) {
      return `${diffHours}小时后`;
    }

    const diffDays = Math.floor(diffHours / 24);
    if (diffDays < 7) {
      return `${diffDays}天后`;
    }

    const diffWeeks = Math.floor(diffDays / 7);
    if (diffWeeks < 4) {
      return `${diffWeeks}周后`;
    }

    const diffMonths = Math.floor(diffDays / 30);
    if (diffMonths < 12) {
      return `${diffMonths}个月后`;
    }

    const diffYears = Math.floor(diffDays / 365);
    return `${diffYears}年后`;
  }

  /**
   * 判断是否为今天
   */
  static isToday(date: Date): boolean {
    const today = new Date();
    return date.getDate() === today.getDate() &&
           date.getMonth() === today.getMonth() &&
           date.getFullYear() === today.getFullYear();
  }

  /**
   * 判断是否为昨天
   */
  static isYesterday(date: Date): boolean {
    const yesterday = this.subtract(new Date(), 'day', 1);
    return date.getDate() === yesterday.getDate() &&
           date.getMonth() === yesterday.getMonth() &&
           date.getFullYear() === yesterday.getFullYear();
  }

  /**
   * 判断是否为明天
   */
  static isTomorrow(date: Date): boolean {
    const tomorrow = this.add(new Date(), 'day', 1);
    return date.getDate() === tomorrow.getDate() &&
           date.getMonth() === tomorrow.getMonth() &&
           date.getFullYear() === tomorrow.getFullYear();
  }

  /**
   * 判断是否为本周
   */
  static isThisWeek(date: Date): boolean {
    const now = new Date();
    const weekStart = this.startOfWeek(now);
    const weekEnd = this.endOfWeek(now);
    return date >= weekStart && date <= weekEnd;
  }

  /**
   * 判断是否为本月
   */
  static isThisMonth(date: Date): boolean {
    const now = new Date();
    return date.getMonth() === now.getMonth() &&
           date.getFullYear() === now.getFullYear();
  }

  /**
   * 判断是否为今年
   */
  static isThisYear(date: Date): boolean {
    const now = new Date();
    return date.getFullYear() === now.getFullYear();
  }

  /**
   * 获取周的开始日期
   */
  static startOfWeek(date: Date, firstDayOfWeek: number = 0): Date {
    const d = new Date(date);
    const day = d.getDay();
    const diff = (day < firstDayOfWeek ? 7 : 0) + day - firstDayOfWeek;
    d.setDate(d.getDate() - diff);
    d.setHours(0, 0, 0, 0);
    return d;
  }

  /**
   * 获取周的结束日期
   */
  static endOfWeek(date: Date, firstDayOfWeek: number = 0): Date {
    const start = this.startOfWeek(date, firstDayOfWeek);
    const end = new Date(start);
    end.setDate(end.getDate() + 6);
    end.setHours(23, 59, 59, 999);
    return end;
  }

  /**
   * 获取月的开始日期
   */
  static startOfMonth(date: Date): Date {
    return new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0, 0);
  }

  /**
   * 获取月的结束日期
   */
  static endOfMonth(date: Date): Date {
    return new Date(date.getFullYear(), date.getMonth() + 1, 0, 23, 59, 59, 999);
  }

  /**
   * 获取年的开始日期
   */
  static startOfYear(date: Date): Date {
    return new Date(date.getFullYear(), 0, 1, 0, 0, 0, 0);
  }

  /**
   * 获取年的结束日期
   */
  static endOfYear(date: Date): Date {
    return new Date(date.getFullYear(), 11, 31, 23, 59, 59, 999);
  }

  /**
   * 比较两个日期
   * [@returns](/user/returns) -1: date1 < date2, 0: date1 == date2, 1: date1 > date2
   */
  static compare(date1: Date, date2: Date): number {
    const time1 = date1.getTime();
    const time2 = date2.getTime();
    if (time1 < time2) return -1;
    if (time1 > time2) return 1;
    return 0;
  }

  /**
   * 判断日期是否在范围内
   */
  static isInRange(date: Date, range: DateRange): boolean {
    return date >= range.start && date <= range.end;
  }

  /**
   * 获取日期范围
   */
  static range(start: Date, end: Date): DateRange {
    return {
      start: start < end ? start : end,
      end: start < end ? end : start
    };
  }

  /**
   * 获取两个日期之间的所有日期
   */
  static datesBetween(start: Date, end: Date): Date[] {
    const dates: Date[] = [];
    const current = new Date(start);
    current.setHours(0, 0, 0, 0);
    const endDate = new Date(end);
    endDate.setHours(0, 0, 0, 0);

    while (current <= endDate) {
      dates.push(new Date(current));
      current.setDate(current.getDate() + 1);
    }
    return dates;
  }

  /**
   * 获取年龄
   */
  static age(birthDate: Date, referenceDate: Date = new Date()): number {
    let age = referenceDate.getFullYear() - birthDate.getFullYear();
    const monthDiff = referenceDate.getMonth() - birthDate.getMonth();
    if (monthDiff < 0 || (monthDiff === 0 && referenceDate.getDate() < birthDate.getDate())) {
      age--;
    }
    return age;
  }

  /**
   * 获取工作日数量(排除周末)
   */
  static weekdaysBetween(start: Date, end: Date): number {
    let count = 0;
    const current = new Date(start);
    current.setHours(0, 0, 0, 0);
    const endDate = new Date(end);
    endDate.setHours(0, 0, 0, 0);

    while (current <= endDate) {
      const day = current.getDay();
      if (day !== 0 && day !== 6) { // 排除周日和周六
        count++;
      }
      current.setDate(current.getDate() + 1);
    }
    return count;
  }

  /**
   * 获取下一个工作日
   */
  static nextWeekday(date: Date): Date {
    let next = this.add(date, 'day', 1);
    while (next.getDay() === 0 || next.getDay() === 6) {
      next = this.add(next, 'day', 1);
    }
    return next;
  }

  /**
   * 获取上一个工作日
   */
  static previousWeekday(date: Date): Date {
    let prev = this.subtract(date, 'day', 1);
    while (prev.getDay() === 0 || prev.getDay() === 6) {
      prev = this.subtract(prev, 'day', 1);
    }
    return prev;
  }

  /**
   * 格式化相对时间(智能显示)
   */
  static smartFormat(date: Date, now: Date = new Date()): string {
    if (this.isToday(date)) {
      return `今天 ${this.format(date, 'HH:mm')}`;
    } else if (this.isYesterday(date)) {
      return `昨天 ${this.format(date, 'HH:mm')}`;
    } else if (this.isTomorrow(date)) {
      return `明天 ${this.format(date, 'HH:mm')}`;
    } else if (this.isThisWeek(date)) {
      return `${this.format(date, 'EEE')} ${this.format(date, 'HH:mm')}`;
    } else if (this.isThisYear(date)) {
      return this.format(date, 'MM-dd HH:mm');
    } else {
      return

更多关于HarmonyOS鸿蒙Next中类似于swiftDate的日期时间操作库的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,推荐使用内置的日期时间处理库@ohos.util.DateTime。该库提供了日期时间的创建、格式化、计算和比较等功能。例如,可以使用DateTime类进行日期时间的加减操作,Time类处理时间相关的计算。此外,@ohos.i18n中的Calendar类支持农历和节假日等高级功能。这些API均基于TypeScript/ArkTS开发,符合鸿蒙应用开发规范。

在HarmonyOS Next中,你可以通过ArkTS的日期时间处理能力,结合扩展封装来实现类似SwiftDate的便捷操作。目前虽然没有完全对等的第三方库,但可以通过以下方式构建:

  1. 使用内置Date对象:ArkTS提供了标准的Date API,支持日期计算、格式化等基础操作。

  2. 封装工具类:建议创建一个DateTime工具类,集成常用功能:

    • 日期解析(支持多种格式字符串)
    • 相对时间计算(如加减天数、月份)
    • 人性化时间显示(如“刚刚”、“3天前”)
    • 时区转换支持
  3. 关键实现示例

// 示例:基础日期操作封装
class DateTimeUtils {
  static addDays(date: Date, days: number): Date {
    let result = new Date(date);
    result.setDate(result.getDate() + days);
    return result;
  }
  
  static formatRelative(date: Date): string {
    // 实现相对时间逻辑
  }
}
  1. 考虑使用扩展方法:通过扩展Date原型或提供静态工具类来增强可读性。

HarmonyOS Next的ArkTS在类型安全和性能方面有良好支持,适合构建这类工具库。建议先明确核心需求,再逐步实现常用功能模块。

回到顶部