Best practice: Làm việc với DateTime

Tìm những records nào liên quan tới ngày đã chọn (Local to UTC)

Bài toán:

  • Tôi muốn lấy dữ liệu hoạt động của 1 user cụ thể trong ngày 12/08/2025 (GMT +8).
  • Giả sử table Logs có các cột như sau “UserId, Data, CreatedOn (UTC)”

Cách thực hiện:

  • Chuyển từ giờ local sang UTC.
  • Cài đặt thời gian bắt đầu 1 ngày và kết thúc của 1 ngày
  • Truy vấn theo khoảng thời gian bắt đầu và kết thúc của ngày đã chọn ở UTC
// Ngày truyền từ Front-end
DateTime localDate = new DateTime(2025, 8, 12);

// Múi giờ UTC+8
TimeZoneInfo utcPlus8 = TimeZoneInfo.FindSystemTimeZoneById("Singapore Standard Time");

// Đầu ngày (00:00:00.000)
DateTime startOfDayLocal = localDate.Date;
DateTime startOfDayUtc = TimeZoneInfo.ConvertTimeToUtc(startOfDayLocal, utcPlus8);

// Cuối ngày (23:59:59.999)
DateTime endOfDayLocal = localDate.Date.AddDays(1).AddMilliseconds(-1);
DateTime endOfDayUtc = TimeZoneInfo.ConvertTimeToUtc(endOfDayLocal, utcPlus8);

// In kết quả
Console.WriteLine("Start of day UTC: " + startOfDayUtc.ToString("yyyy-MM-dd HH:mm:ss.fff") + "Z");
Console.WriteLine("End of day UTC:   " + endOfDayUtc.ToString("yyyy-MM-dd HH:mm:ss.fff") + "Z");

// Truy vấn
var checkInLogs = _context.Logs.Where(p => p.CreatedOn >= startOfDayUtc && p.CreatedOn <= endOfDayUtc).ToList();

Xây dựng phân đoạn Active của users.

Bài toán:

  • Có 1 table UserActivities (ShiftId, UserId, Type, ActionDateTime)
  • Type: Add, Remove (User được thêm hoặc xóa ra khỏi Shift theo thời gian nhất định)
  • Yêu cầu in ra danh sách khoản thời gian nào user được thêm vào và cho đến khi bị xóa ra khỏi shift.

Cách thực hiện:

  • Chia phân đoạn cho user đó
var data = new List<UserHistory>
{
    new UserHistory
    {
        Name = "A",
        CreatedOn = DateTime.Parse("08/10/2025 07:06:13"),
        Type = "Add"
    },
    new UserHistory
    {
        Name = "A",
        CreatedOn = DateTime.Parse("08/12/2025 07:06:13"),
        Type = "Remove"
    },
    new UserHistory
    {
        Name = "A",
        CreatedOn = DateTime.Parse("08/13/2025 07:06:13"),
        Type = "Add"
    },
    new UserHistory
    {
        Name = "A",
        CreatedOn = DateTime.Parse("08/13/2025 08:06:13"),
        Type = "Remove"
    },
    new UserHistory
    {
        Name = "A",
        CreatedOn = DateTime.Parse("08/13/2025 09:06:13"),
        Type = "Add"
    },
    new UserHistory
    {
        Name = "A",
        CreatedOn = DateTime.Parse("08/14/2025 07:06:13"),
        Type = "Add"
    }
};

var selectedDate = DateTime.Parse("08/13/2025 23:59:59");


var activeSegments = new List<ActiveSegment>();
var currentSegment = new Dictionary<string, DateTime>();

var filteredData = data.Where(p => p.CreatedOn <= selectedDate).OrderBy(p => p.CreatedOn);
foreach (var segment in filteredData)
{
    var userName = segment.Name;
    DateTime startTime;
    var currentItem = currentSegment.TryGetValue(segment.Name, out startTime);
    if(currentItem == false)
    {
        // Create new segment
        currentSegment[userName] = segment.CreatedOn;
    }
    else
    {
        if(segment.Type == "Remove")
        {
            activeSegments.Add(new ActiveSegment
            {
                Name = userName,
                Start = startTime,
                End = segment.CreatedOn
            });
            currentSegment.Remove(userName);
        }
    }
}

// Acc to active segment if user is dont have End
var dontRemoved = currentSegment;
foreach (var item in dontRemoved)
{
    activeSegments.Add(new ActiveSegment
    {
        Name = item.Key,
        Start = item.Value
    });
}

foreach (var item in activeSegments)
{
    Console.WriteLine($"{item.Name}, {item.Start}, {item.End}");
}

To be continue……

F G+ T

tuandph

Khởi đầu với .NET từ năm 2013 đến nay. Hiện tại mình đang làm full-stack developer. Yêu thích lập trình & chia sẽ kiến thức. Thời gian rảnh thường làm những tool vui vui và viết lách kể lệ sự đời.