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)),), ), ); } }
问题原因
- 月份参数错误:
Random().nextInt(12)生成的是0-11的整数,而Dart的DateTime构造函数中,月份参数是从1开始的(1代表1月,12代表12月)。当传入0时,DateTime会自动向前推算,将年份减1,月份变为12,这就导致了2021年日期的出现。 - 日期参数错误:
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
相关产品推荐
相关产品推荐

