13-Random 和 DateTime
一、Random(随机数)
Random 类用于生成随机数,位于 System 命名空间。
1. Random 的两种创建方式
csharp
// 方式一:无种子——基于当前时间自动生成种子
Random rnd = new Random();
// 每次运行产生不同的随机序列
// 方式二:指定种子——相同种子产生相同的序列
Random rnd2 = new Random(12345);
// 调试和测试时使用,保证可重复性种子选择的重要性:
- 无种子:基于系统时钟,每次运行结果不同
- 固定种子:结果可重现,适合测试场景
- 不要在循环中重复创建:同一时钟滴答内创建的多个对象会产生相同序列
csharp
// ❌ 错误:循环中重复创建
for (int i = 0; i < 5; i++)
{
Random bad = new Random(); // 可能使用相同的时间种子
Console.WriteLine(bad.Next(100)); // 可能打印相同的数字
}
// ✅ 正确:只创建一次,重复使用
Random good = new Random();
for (int i = 0; i < 5; i++)
{
Console.WriteLine(good.Next(100)); // 每次不同
}2. 常用方法详解
| 方法 | 签名 | 范围 | 示例 |
|---|---|---|---|
Next() | int Next() | 0 ~ int.MaxValue | rnd.Next() → 某个正随机整数 |
Next(Int32) | int Next(int maxValue) | 0 ~ (maxValue-1) | rnd.Next(100) → 0~99 |
Next(Int32,Int32) | int Next(int min, int max) | min ~ (max-1) | rnd.Next(1,7) → 1~6(掷骰子) |
NextDouble() | double NextDouble() | 0.0 ~ 1.0 | rnd.NextDouble() → 0.0~1.0 |
NextBytes() | void NextBytes(byte[]) | 0 ~ 255 | 填充字节数组 |
csharp
Random rnd = new Random();
// 各种范围的随机数
int dice = rnd.Next(1, 7); // 1~6(模拟骰子)
int score = rnd.Next(101); // 0~100(随机分数)
int year = rnd.Next(2020, 2025); // 2020~2024(随机年份)
double percent = rnd.NextDouble(); // 0.0~1.0(百分比)
double price = Math.Round(rnd.NextDouble() * 1000, 2); // 0.00~1000.00(价格)
double temperature = Math.Round(rnd.NextDouble() * 60 - 20, 1); // -20~40(温度)
// 随机布尔值
bool coinFlip = rnd.Next(2) == 0;
bool lucky = rnd.NextDouble() < 0.3; // 30% 的概率3. 实际应用场景
场景一:随机抽奖
csharp
static string LotteryDraw(string[] participants, int winnerCount)
{
if (participants.Length < winnerCount)
return "参与人数不足";
Random rnd = new Random();
// 打乱顺序
string[] shuffled = participants.OrderBy(_ => rnd.Next()).ToArray();
return $"中奖者:{string.Join("、", shuffled.Take(winnerCount))}";
}
string[] names = { "张三", "李四", "王五", "赵六", "钱七" };
Console.WriteLine(LotteryDraw(names, 2));场景二:模拟掷骰子
csharp
static int RollDice(int sides = 6)
{
return new Random().Next(1, sides + 1);
}
// 多次掷骰子统计
Random rnd = new Random();
int[] counts = new int[6];
for (int i = 0; i < 6000; i++)
{
int result = rnd.Next(1, 7); // 1~6
counts[result - 1]++;
}
for (int i = 0; i < 6; i++)
{
Console.WriteLine($"点数 {i + 1}:{counts[i]} 次({counts[i] / 60.0:F1}%)");
}场景三:生成验证码
csharp
static string GenerateCaptcha(int length)
{
const string chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; // 排除易混淆字符(0,O,1,I)
Random rnd = new Random();
char[] result = new char[length];
for (int i = 0; i < length; i++)
result[i] = chars[rnd.Next(chars.Length)];
return new string(result);
}
Console.WriteLine($"验证码:{GenerateCaptcha(4)}");
Console.WriteLine($"验证码:{GenerateCaptcha(6)}");场景四:洗牌算法(Fisher-Yates)
csharp
static void Shuffle<T>(T[] array)
{
Random rnd = new Random();
for (int i = array.Length - 1; i > 0; i--)
{
int j = rnd.Next(0, i + 1);
// 交换 array[i] 和 array[j]
(array[i], array[j]) = (array[j], array[i]);
}
}
int[] cards = Enumerable.Range(1, 52).ToArray(); // 52 张牌
Shuffle(cards);
Console.WriteLine($"洗牌后前5张:{string.Join(", ", cards.Take(5))}");二、DateTime(日期时间)
DateTime 用于处理日期和时间,支持时区、运算、格式化等操作。
1. 创建 DateTime 对象
csharp
// 获取当前时间
DateTime now = DateTime.Now; // 本地时间:2024-10-01 14:30:00
DateTime utcNow = DateTime.UtcNow; // UTC 时间:2024-10-01 06:30:00
DateTime today = DateTime.Today; // 当天日期(时间部分为 00:00:00)
// 指定日期时间
DateTime d1 = new DateTime(2024, 1, 1); // 2024-01-01 00:00:00
DateTime d2 = new DateTime(2024, 10, 1, 14, 30, 0); // 2024-10-01 14:30:00
DateTime d3 = new DateTime(2024, 12, 31, 23, 59, 59, 999); // 含毫秒
// 从字符串解析
DateTime parsed = DateTime.Parse("2024-10-01");
DateTime parsed2 = DateTime.Parse("2024/10/01 14:30:00");
// 安全解析(推荐,避免异常)
if (DateTime.TryParse("2024-13-01", out DateTime result))
{
Console.WriteLine($"解析成功:{result}");
}
else
{
Console.WriteLine("日期格式无效"); // 会执行这里
}DateTime 与 DateTimeOffset
csharp
// DateTime:可以包含时区信息,但容易混淆
DateTime localTime = DateTime.Now; // 本地时间
DateTime utcTime = DateTime.UtcNow; // UTC 时间
// DateTimeOffset:明确包含时区偏移
DateTimeOffset nowWithOffset = DateTimeOffset.Now;
Console.WriteLine(nowWithOffset); // 2024-10-01 14:30:00 +08:00
// 跨时区存储时推荐 DateTimeOffset2. 常用属性
csharp
DateTime now = DateTime.Now;
Console.WriteLine($"完整时间:{now}"); // 2024-10-01 14:30:00
Console.WriteLine($"年:{now.Year}"); // 2024
Console.WriteLine($"月:{now.Month}"); // 10
Console.WriteLine($"日:{now.Day}"); // 1
Console.WriteLine($"时:{now.Hour}"); // 14
Console.WriteLine($"分:{now.Minute}"); // 30
Console.WriteLine($"秒:{now.Second}"); // 0
Console.WriteLine($"毫秒:{now.Millisecond}"); // 123
Console.WriteLine($"星期:{now.DayOfWeek}"); // Tuesday
Console.WriteLine($"一年中第几天:{now.DayOfYear}"); // 275
Console.WriteLine($"日期部分:{now.Date}"); // 2024-10-01 00:00:00
Console.WriteLine($"时间部分:{now.TimeOfDay}"); // 14:30:00.12300003. 日期运算
添加时间间隔
csharp
DateTime today = DateTime.Today;
DateTime tomorrow = today.AddDays(1); // 明天
DateTime yesterday = today.AddDays(-1); // 昨天
DateTime nextWeek = today.AddDays(7); // 一周后
DateTime lastMonth = today.AddMonths(-1); // 上个月
DateTime nextYear = today.AddYears(1); // 明年
DateTime noon = today.AddHours(12); // 今天中午
DateTime midNight = today.AddMinutes(1); // 明天 00:01
// 计算月末最后一天
DateTime firstDay = new DateTime(2024, 2, 1);
DateTime lastDay = firstDay.AddMonths(1).AddDays(-1);
Console.WriteLine(lastDay.ToString("yyyy-MM-dd")); // 2024-02-29(闰年)日期差值计算
csharp
DateTime start = new DateTime(2024, 1, 1);
DateTime end = new DateTime(2024, 12, 31);
// 计算差值(TimeSpan)
TimeSpan diff = end - start;
Console.WriteLine($"总天数:{diff.Days}"); // 365
Console.WriteLine($"总小时数:{diff.TotalHours}"); // 8760
Console.WriteLine($"总分钟数:{diff.TotalMinutes}"); // 525600
// 计算两个日期之间的工作日数
static int WorkDaysBetween(DateTime start, DateTime end)
{
int workDays = 0;
for (DateTime d = start; d <= end; d = d.AddDays(1))
{
if (d.DayOfWeek != DayOfWeek.Saturday && d.DayOfWeek != DayOfWeek.Sunday)
workDays++;
}
return workDays;
}
Console.WriteLine($"工作日:{WorkDaysBetween(start, end)}");4. 日期格式化
csharp
DateTime now = DateTime.Now;
// 常用标准格式
string[] formats =
{
now.ToString("yyyy-MM-dd"), // 2024-10-01(ISO 格式)
now.ToString("yyyy/MM/dd"), // 2024/10/01
now.ToString("yyyyMMdd"), // 20241001(紧凑格式)
now.ToString("yyyy-MM-dd HH:mm:ss"), // 2024-10-01 14:30:00
now.ToString("yyyy-MM-dd HH:mm:ss.fff"), // 2024-10-01 14:30:00.123(含毫秒)
now.ToString("HH:mm:ss"), // 14:30:00(仅时间)
now.ToString("dddd"), // 星期二
now.ToString("ddd"), // 周二
now.ToString("yyyy年MM月dd日 dddd"), // 2024年10月01日 星期二
now.ToString("hh:mm tt"), // 02:30 下午(12小时制)
now.ToString("yyyy-MM-ddTHH:mm:ssZ"), // 2024-10-01T14:30:00Z(ISO 8601)
};
// 标准格式说明符
Console.WriteLine(now.ToString("d")); // 短日期:2024/10/1
Console.WriteLine(now.ToString("D")); // 长日期:2024年10月1日
Console.WriteLine(now.ToString("t")); // 短时间:14:30
Console.WriteLine(now.ToString("T")); // 长时间:14:30:00
Console.WriteLine(now.ToString("f")); // 完整日期+短时间:2024年10月1日 14:30
Console.WriteLine(now.ToString("F")); // 完整日期+长时间:2024年10月1日 14:30:00
Console.WriteLine(now.ToString("g")); // 短日期+短时间:2024/10/1 14:30
Console.WriteLine(now.ToString("G")); // 短日期+长时间:2024/10/1 14:30:00三、TimeSpan(时间间隔)
TimeSpan 表示一段时间间隔,常用于计算耗时、日期差等。
创建方式
csharp
// 通过构造函数
TimeSpan ts1 = new TimeSpan(1, 30, 0); // 1小时30分钟
TimeSpan ts2 = new TimeSpan(1, 2, 30, 0); // 1天2小时30分钟
TimeSpan ts3 = new TimeSpan(1, 2, 30, 0, 500); // 1天2小时30分钟500毫秒
// 通过静态方法(更直观)
TimeSpan fromDays = TimeSpan.FromDays(7); // 7天
TimeSpan fromHours = TimeSpan.FromHours(2.5); // 2.5小时
TimeSpan fromMinutes = TimeSpan.FromMinutes(90); // 90分钟
TimeSpan fromSeconds = TimeSpan.FromSeconds(45); // 45秒
TimeSpan fromMs = TimeSpan.FromMilliseconds(500); // 500毫秒属性和方法
csharp
TimeSpan duration = new TimeSpan(2, 5, 30, 15); // 2天5小时30分钟15秒
// 组成属性
Console.WriteLine($"天:{duration.Days}"); // 2
Console.WriteLine($"小时:{duration.Hours}"); // 5
Console.WriteLine($"分钟:{duration.Minutes}"); // 30
Console.WriteLine($"秒:{duration.Seconds}"); // 15
// 总属性(以该单位表示的完整时间)
Console.WriteLine($"总天数:{duration.TotalDays}"); // 2.229...
Console.WriteLine($"总小时数:{duration.TotalHours}"); // 53.504...
Console.WriteLine($"总分钟数:{duration.TotalMinutes}"); // 3210.25
Console.WriteLine($"总秒数:{duration.TotalSeconds}"); // 192615
Console.WriteLine($"总毫秒数:{duration.TotalMilliseconds}"); // 192615000
// 运算
TimeSpan add = duration.Add(TimeSpan.FromHours(1));
TimeSpan sub = duration.Subtract(TimeSpan.FromDays(1));计时器:测量代码执行时间
csharp
// 使用 Stopwatch(推荐)——更精准
Stopwatch sw = Stopwatch.StartNew();
// 模拟耗时操作
Thread.Sleep(100);
sw.Stop();
Console.WriteLine($"耗时:{sw.ElapsedMilliseconds} 毫秒");
Console.WriteLine($"耗时:{sw.Elapsed.TotalSeconds:F3} 秒");
// 使用 DateTime
DateTime start = DateTime.Now;
Thread.Sleep(100);
DateTime end = DateTime.Now;
Console.WriteLine($"耗时:{(end - start).TotalMilliseconds:F0} 毫秒");四、综合案例
案例一:年龄计算器
csharp
static int CalculateAge(DateTime birthDate)
{
DateTime today = DateTime.Today;
int age = today.Year - birthDate.Year;
// 如果今年生日还没过,减一岁
if (birthDate > today.AddYears(-age))
age--;
return age;
}
// 计算到生日的天数
static int DaysToBirthday(DateTime birthDate)
{
DateTime today = DateTime.Today;
DateTime nextBirthday = new DateTime(today.Year, birthDate.Month, birthDate.Day);
if (nextBirthday < today)
nextBirthday = nextBirthday.AddYears(1);
return (nextBirthday - today).Days;
}
// 使用
DateTime birth = new DateTime(1990, 5, 15);
Console.WriteLine($"年龄:{CalculateAge(birth)}"); // 输出:34
Console.WriteLine($"距离下次生日:{DaysToBirthday(birth)}天");案例二:随机数据生成器
csharp
class RandomDataGenerator
{
private static readonly Random rnd = new Random();
private static readonly string[] LastNames = { "张", "李", "王", "赵", "刘", "陈" };
private static readonly string[] FirstNames = { "伟", "强", "丽", "敏", "静", "涛" };
public static string GenerateName()
{
return LastNames[rnd.Next(LastNames.Length)] + FirstNames[rnd.Next(FirstNames.Length)];
}
public static DateTime GenerateBirthDate(int minAge = 18, int maxAge = 60)
{
int age = rnd.Next(minAge, maxAge + 1);
return DateTime.Today.AddYears(-age).AddDays(-rnd.Next(365));
}
public static string GenerateIdNumber()
{
return string.Join("", Enumerable.Range(0, 18).Select(_ => rnd.Next(10)));
}
public static decimal GenerateSalary(decimal min = 3000, decimal max = 30000)
{
return Math.Round((decimal)(min + rnd.NextDouble() * (double)(max - min)), 2);
}
public static (string Name, int Age, DateTime Birth, decimal Salary) GenerateEmployee()
{
DateTime birth = GenerateBirthDate();
return (GenerateName(), CalculateAge(birth), birth, GenerateSalary());
}
// 复用年龄计算方法
static int CalculateAge(DateTime birth) => new DateTime(2024, 1, 1).Year - birth.Year;
}
// 生成员工数据
for (int i = 0; i < 5; i++)
{
var emp = RandomDataGenerator.GenerateEmployee();
Console.WriteLine($"{emp.Name}\t{emp.Age}岁\t{emp.Salary:C}");
}案例三:日志时间戳
csharp
class Logger
{
public static void Info(string message)
{
string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
Console.WriteLine($"[{timestamp}] [INFO] {message}");
}
public static void Error(string message)
{
string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
Console.WriteLine($"[{timestamp}] [ERROR] {message}");
}
public static void Measure(string taskName, Action action)
{
Stopwatch sw = Stopwatch.StartNew();
action();
sw.Stop();
Info($"{taskName} 耗时 {sw.ElapsedMilliseconds}ms");
}
}
// 使用
Logger.Info("系统启动");
Logger.Measure("数据处理", () => Thread.Sleep(200));
Logger.Error("数据库连接超时");核心知识点总结
Random
| 方法 | 作用 | 范围 |
|---|---|---|
Next() | 随机整数 | 0 ~ int.MaxValue |
Next(max) | 随机整数 | 0 ~ max-1 |
Next(min, max) | 随机整数 | min ~ max-1 |
NextDouble() | 随机浮点数 | 0.0 ~ 1.0 |
注意事项:
- 一个程序只创建一个
Random实例,不要重复创建 - 固定种子用于测试,无种子用于正式运行
- 不是密码学安全的随机数——需要安全随机时用
System.Security.Cryptography.RandomNumberGenerator
DateTime
| 属性/方法 | 说明 |
|---|---|
Now | 当前本地日期时间 |
UtcNow | 当前 UTC 日期时间 |
Today | 当天日期(00:00) |
AddDays/Months/Years/Hours | 添加时间间隔 |
ToString(format) | 格式化为字符串 |
TryParse(str, out dt) | 安全解析字符串 |
时间标准选择:
- 用户界面显示:
DateTime.Now - 数据存储/跨时区:
DateTime.UtcNow或DateTimeOffset - 纯日期(无时间):
DateTime.Today - 文件命名:
yyyy-MM-dd-HH-mm-ss
TimeSpan
- 表示两个时间点之间的间隔
Days/Hours/Minutes/Seconds返回组成部分TotalDays/TotalHours等返回以该单位表示的完整间隔DateTime相减得到TimeSpanStopwatch是测量代码执行时间的最佳选择


