You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter真机中_pickedTime.format(context)转换TimeOfDay为String报错求助

问题原因

错误Trying to read from 08:43 at position 6是因为真实设备与模拟器的区域设置不同,导致TimeOfDay.format(context)返回的时间字符串格式不一致:

  • 模拟器可能返回带AM/PM的12小时制格式(如08:43 AM)
  • 真实设备可能返回不带AM/PM的24小时制格式(如08:43)

当你用DateFormat.jm()(专门解析带AM/PM的12小时制字符串)去解析24小时制字符串时,解析器会尝试读取AM/PM部分(对应字符串索引6的位置),但24小时制字符串长度不足,因此抛出索引越界错误。

另外,代码还存在空指针隐患:用户取消时间选择时pickedTime为null,直接调用pickedTime.format(context)会崩溃。

解决方案

1. 取消依赖系统区域的时间格式化,改用自定义固定格式

避免TimeOfDay.format(context)带来的格式差异,自己实现固定格式的时间转换:

// 自定义12小时制格式化(带AM/PM)
String formatTimeOfDay(TimeOfDay time) {
  final period = time.hour >= 12 ? 'PM' : 'AM';
  final displayHour = time.hour % 12 == 0 ? 12 : time.hour % 12;
  return '${displayHour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')} $period';
}

// 或者自定义24小时制格式化
String formatTimeOfDay24(TimeOfDay time) {
  return '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}';
}

2. 修复空指针问题,修改_getTimeFromUser方法

先判断用户是否取消选择,再处理时间格式化:

_getTimeFromUser({required bool isStartTime}) async {
  final pickedTime = await _showTimePicker();
  if (pickedTime == null) {
    debugPrint('Time Cancelled');
    return;
  }
  
  // 使用自定义格式化方法替代系统format
  final formattedTime = formatTimeOfDay(pickedTime);
  setState(() {
    if (isStartTime) {
      _startTime = formattedTime;
    } else {
      _endTime = formattedTime;
    }
  });
}

3. 统一时间解析逻辑

如果task.startTime是用自定义格式生成的,解析时要匹配对应的DateFormat:

  • 若用12小时制带AM/PM,继续用DateFormat.jm()解析
  • 若用24小时制,改用DateFormat.Hm()解析

修改解析代码:

// 假设task.startTime是24小时制格式,用DateFormat.Hm()解析
DateTime date = DateFormat.Hm().parse(task.startTime);
final myTime = DateFormat("HH:mm").format(date);
notificationService.scheduleNotification(
  hour: int.parse(myTime.split(":")[0]),
  minutes: int.parse(myTime.split(":")[1]),
  task: task
);

4. 优化_showTimePicker的初始化逻辑

确保初始化TimeOfDay时,拆分逻辑匹配自定义格式:

// 针对12小时制格式拆分(如"08:43 AM")
_showTimePicker() {
  final timeParts = _startTime.split(':');
  final hourPart = timeParts[0];
  final minutePeriodPart = timeParts[1].split(' ');
  final minutePart = minutePeriodPart[0];
  final period = minutePeriodPart[1];
  
  int hour = int.parse(hourPart);
  if (period == 'PM' && hour != 12) {
    hour += 12;
  } else if (period == 'AM' && hour == 12) {
    hour = 0;
  }
  
  return showTimePicker(
    context: context,
    initialEntryMode: TimePickerEntryMode.input,
    initialTime: TimeOfDay(hour: hour, minute: int.parse(minutePart)),
  );
}

// 如果用24小时制格式,拆分更简单:
// _showTimePicker() {
//   final timeParts = _startTime.split(':');
//   return showTimePicker(
//     context: context,
//     initialEntryMode: TimePickerEntryMode.input,
//     initialTime: TimeOfDay(
//       hour: int.parse(timeParts[0]),
//       minute: int.parse(timeParts[1]),
//     ),
//   );
// }
总结

核心思路是统一时间的格式化和解析规则,避免依赖系统区域设置带来的格式差异,同时修复空指针隐患,这样无论在真实设备还是模拟器上,时间处理逻辑都会保持一致。

内容的提问来源于stack exchange,提问作者Emeka Jide

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 08:05:26