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

Flutter中使用Random函数生成DateTime值不符合预期

日期生成异常问题分析与解决

问题描述

编写了生成ExpenseModel对象的函数,固定日期年份为2022,随机生成月份和28以内的日期,但实际运行后出现了2021年的日期,同时也出现了31号的日期,无法定位问题原因。

相关代码

生成费用的函数

void createexpenses() {
    expensies.clear();
    for (int x = 1; x <= 50; x++) {
      expensies.add(ExpenseModel(
          category: categories[Random().nextInt(6)],
          amount: Random().nextInt(100),
          date: DateTime(2022, Random().nextInt(12), Random().nextInt(28))));
      // 此处设置固定年份2022,日期限制在28以内
    }
}

ExpenseModel类

class ExpenseModel
{
  String category;
  int amount;
  DateTime date;

  ExpenseModel({required this.category,required this.amount,required this.date});
}

页面构建代码

Widget build(BuildContext context) {
    createexpenses(); // 创建50个ExpenseModel对象
    return Scaffold(
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 10.0),
          child: Column(
            children: [
              StatusWidget(amount:totalexpense),
              SizedBox(
                height: 10,
              ),
              Expanded(
                  child: ListView.builder(
                      itemCount: expensies.length,
                      itemBuilder: (context, index) {
                        final data = expensies[index];
                        return Padding(
                          padding: const EdgeInsets.only(bottom: 8.0),
                          child: ExpenseTile(data: data),
                        );
                      }))
            ],
          ),
        ),
      ),
    );
  }

ExpenseTile组件

class ExpenseTile extends StatelessWidget {

  ExpenseModel data;
  ExpenseTile({Key? key,required this.data}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.symmetric(vertical: 15),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(20),
        color: Colors.grey[200],

      ),
      child: ListTile(
        title: Text(data.category.toString()),
        trailing: Container(
          decoration: BoxDecoration(
            color: Colors.grey[300],
            borderRadius: BorderRadius.circular(20),

          ),
            padding: EdgeInsets.all(10),
            child: Text(data.amount.toDouble().toString(),style: TextStyle(fontSize: 20,fontWeight: FontWeight.bold),)),
        subtitle: Text(DateFormat("dd-MM-yyyy").format(data.date)),
        leading: CircleAvatar(child: Text(data.category.substring(0,1)),),
      ),
    );
  }
}

问题原因

  1. 月份参数错误:Random().nextInt(12)生成的是0-11的整数,而Dart的DateTime构造函数中,月份参数是从1开始的(1代表1月,12代表12月)。当传入0时,DateTime会自动向前推算,将年份减1,月份变为12,这就导致了2021年日期的出现。
  2. 日期参数错误:Random().nextInt(28)生成的是0-27的整数,DateTime的日期参数如果传入0,会自动推算到上个月的最后一天。比如传入DateTime(2022, 1, 0)会得到2021年12月31日,这就出现了31号的日期。

解决方案

修正日期生成逻辑

将月份和日期的随机生成逻辑调整为从1开始:

  • 月份:Random().nextInt(12) + 1,生成1-12的整数,对应正确的1-12月
  • 日期:Random().nextInt(28) + 1,生成1-28的整数,避免传入0导致的日期回退

同时建议只创建一个Random实例,避免循环中重复创建,提升效率和随机数分布均匀性。修改后的函数代码如下:

void createexpenses() {
  expensies.clear();
  final random = Random();
  for (int x = 1; x <= 50; x++) {
    expensies.add(ExpenseModel(
        category: categories[random.nextInt(6)],
        amount: random.nextInt(100),
        date: DateTime(2022, random.nextInt(12) + 1, random.nextInt(28) + 1)));
  }
}

额外优化建议

不要在build方法中调用createexpenses(),因为每次页面重绘都会重新生成数据,可能引发不必要的性能损耗和数据波动。如果是StatefulWidget,建议将该方法移到initState()中,确保只在初始化时生成一次数据。

内容的提问来源于stack exchange,提问作者Irfan Ganatra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 23:25:35