在这里插入图片描述

时间戳是Unix时间的表示方式,在Web开发中经常用到。今天我们实现一个时间戳转换工具,让时间戳和日期时间之间的转换变得简单。

拆分实现思路

这个页面来自真实的助手工具项目,我把关键路径拆成小片段,方便理解和复用。每段代码后面都会补充具体的使用场景和注意点。

0) 依赖与入口挂载

import 'package:intl/intl.dart';
import 'package:get/get.dart';

说明:

  • intl负责日期格式化,实际项目里一般统一在一个工具类中封装,但页面内部直接用也足够清晰。
  • get用来弹出提示,轻量、少样板,适合工具类页面的反馈。
// 路由入口
GetPage(
  name: '/timestamp',
  page: () => const TimestampConverterPage(),
),

说明:

  • 时间戳工具一般是“工具箱”里的子页面,路由注册是第一步。
  • 真实项目里不会把页面挂在首页,独立路由能保持结构清爽。

1) 页面入口与状态

class TimestampConverterPage extends StatefulWidget {
  const TimestampConverterPage({Key? key}) : super(key: key);

  
  State<TimestampConverterPage> createState() => _TimestampConverterPageState();
}

class _TimestampConverterPageState extends State<TimestampConverterPage> {
  final TextEditingController _timestampController = TextEditingController();
  DateTime _selectedDateTime = DateTime.now();
  bool _isMilliseconds = true;
}

说明:

  • TextEditingController负责时间戳输入的读写,便于按钮点击时拿到最新值。
  • _selectedDateTime作为页面统一的时间状态,后面的结果面板都从这里读。
  • _isMilliseconds用来区分秒/毫秒,这个开关决定解析逻辑。

2) 初始化时填充当前时间戳


void initState() {
  super.initState();
  _updateTimestamp();
}

说明:

  • 进入页面先填一次时间戳,避免空白态。
  • 真实项目里用户更希望“打开即用”,而不是先输入。

3) 当前时间卡片

Card(
  color: Colors.blue[50],
  child: Padding(
    padding: EdgeInsets.all(16.w),
    child: Column(
      children: [
        Text('当前时间', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold)),
        SizedBox(height: 8.h),
        Text(
          DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()),
          style: TextStyle(fontSize: 20.sp, fontWeight: FontWeight.bold, color: Colors.blue[900]),
        ),
        SizedBox(height: 8.h),
        Text(
          '时间戳: ${DateTime.now().millisecondsSinceEpoch}',
          style: TextStyle(fontSize: 14.sp, fontFamily: 'monospace'),
        ),
      ],
    ),
  ),
)

说明:

  • 这里展示“当前时间 + 当前时间戳”,用户对比最直观。
  • DateFormat来自 intl,项目里一般会全局封装,但本例直接用更清晰。

4) 时间戳输入与复制

TextField(
  controller: _timestampController,
  keyboardType: TextInputType.number,
  style: TextStyle(fontSize: 18.sp, fontFamily: 'monospace'),
  decoration: InputDecoration(
    hintText: '输入时间戳...',
    border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.r)),
    suffixIcon: IconButton(
      icon: const Icon(Icons.copy),
      onPressed: () => _copy(_timestampController.text),
    ),
  ),
)

说明:

  • 输入框启用数字键盘,避免用户输入非数字。
  • 右侧复制按钮是常见交互,小工具类应用很吃这个细节。

5) 毫秒/秒切换 + 转换按钮

Row(
  children: [
    Checkbox(
      value: _isMilliseconds,
      onChanged: (v) => setState(() => _isMilliseconds = v ?? true),
    ),
    const Text('毫秒'),
    SizedBox(width: 16.w),
    ElevatedButton(
      onPressed: _parseTimestamp,
      child: const Text('转换为日期'),
    ),
  ],
)

说明:

  • 真实项目里不少后端返回的是秒级时间戳,这个切换很必要。
  • 点击按钮走解析逻辑,避免输入框变化就频繁解析。

6) 时间戳解析逻辑

void _parseTimestamp() {
  final timestamp = int.tryParse(_timestampController.text);
  if (timestamp == null) {
    Get.snackbar('错误', '请输入有效的时间戳', snackPosition: SnackPosition.BOTTOM);
    return;
  }

  setState(() {
    _selectedDateTime = DateTime.fromMillisecondsSinceEpoch(
      _isMilliseconds ? timestamp : timestamp * 1000,
    );
  });
}

说明:

  • int.tryParse可以避免异常,输入不合法直接提示。
  • 关键点是秒转毫秒:timestamp * 1000,不少人踩过这个坑。

7) 日期与时间选择

ListTile(
  leading: const Icon(Icons.calendar_today),
  title: Text(DateFormat('yyyy-MM-dd').format(_selectedDateTime)),
  trailing: const Icon(Icons.arrow_forward_ios),
  onTap: _pickDate,
),

说明:

  • ListTile 做入口,保持一致的列表样式。
  • 日期和时间拆开选择,用户操作成本更低。
Future<void> _pickDate() async {
  final date = await showDatePicker(
    context: context,
    initialDate: _selectedDateTime,
    firstDate: DateTime(1970),
    lastDate: DateTime(2100),
  );
  if (date != null) {
    setState(() {
      _selectedDateTime = DateTime(
        date.year,
        date.month,
        date.day,
        _selectedDateTime.hour,
        _selectedDateTime.minute,
        _selectedDateTime.second,
      );
      _updateTimestamp();
    });
  }
}

说明:

  • 选择日期后保留原来的时分秒,体验更连贯。
  • 调用 _updateTimestamp() 保证输入框的时间戳同步更新。
Future<void> _pickTime() async {
  final time = await showTimePicker(
    context: context,
    initialTime: TimeOfDay.fromDateTime(_selectedDateTime),
  );
  if (time != null) {
    setState(() {
      _selectedDateTime = DateTime(
        _selectedDateTime.year,
        _selectedDateTime.month,
        _selectedDateTime.day,
        time.hour,
        time.minute,
      );
      _updateTimestamp();
    });
  }
}

说明:

  • 时间选择和日期选择拆开,减少用户一次性操作压力。
  • 更新后统一调用 _updateTimestamp(),保证结果区和输入框一致。

8) 结果展示行

Widget _buildResultRow(String label, String value) {
  return Padding(
    padding: EdgeInsets.symmetric(vertical: 4.h),
    child: Row(
      children: [
        SizedBox(
          width: 100.w,
          child: Text(label, style: TextStyle(fontSize: 13.sp, color: Colors.grey[700])),
        ),
        Expanded(
          child: Container(
            padding: EdgeInsets.all(8.w),
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(4.r),
            ),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Expanded(
                  child: Text(value, style: TextStyle(fontSize: 13.sp, fontFamily: 'monospace')),
                ),
                IconButton(
                  icon: const Icon(Icons.copy, size: 18),
                  onPressed: () => _copy(value),
                  padding: EdgeInsets.zero,
                  constraints: const BoxConstraints(),
                ),
              ],
            ),
          ),
        ),
      ],
    ),
  );
}

说明:

  • 这段是复用组件,真实页面里会被多次调用。
  • value采用等宽字体,方便用户比对时间戳长度。

9) 复制反馈

void _copy(String text) {
  Clipboard.setData(ClipboardData(text: text));
  Get.snackbar('成功', '已复制', snackPosition: SnackPosition.BOTTOM, duration: const Duration(seconds: 2));
}

说明:

  • 轻量提示足够,避免弹窗打断流程。
  • Get.snackbar 在 OpenHarmony Web 的小工具类页面里非常实用。

10) 时间戳同步

void _updateTimestamp() {
  setState(() {
    _timestampController.text = _selectedDateTime.millisecondsSinceEpoch.toString();
  });
}

说明:

  • 用户从“日期→时间戳”路径时,输入框的值必须跟着更新。
  • 这里用 setState 保证结果面板也能一起刷新。

小结

本工具的关键点在于:统一使用 _selectedDateTime 做状态来源、解析时处理秒/毫秒差异、并且保持输入框与选择器的同步。这样即使页面看起来简单,也能在真实项目中稳定运行。


欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐