# Phương pháp quy chiếu xác định ranh giới ngày dân sự (Reference Method for Determining a Civil Day Boundary)

<!--
  Document ID: QP-EXAMPLE-001
  Version: 1.0.0
  Profile: QPS-ISO 1.0
  Classification: method
  Language: vi (Canonical)
-->

## Abstract

**Background / Problem:** Trong tính toán lịch âm dương và hệ thống thiên văn Quizzman, việc xác định ranh giới ngày dân sự (civil day boundary) tại thời điểm nửa đêm cục bộ là tiền đề bắt buộc để phân định ngày đầu tháng (sóc / new moon) và tiết khí. Sự thiếu nhất quán giữa múi giờ quy chiếu và thang đo thời gian có thể dẫn đến lệch nguyên một ngày lịch.  
**Method:** Tài liệu này chuẩn hóa phương pháp quy chiếu toán học xác định thời khắc chuyển giao ngày dân sự dựa trên thời gian thực địa phương gắn với kinh tuyến quy chiếu, tuân thủ nguyên tắc ISO 8601 và thuật toán khử thời gian động học của Meeus.  
**Results:** Thuật toán đề xuất được kiểm chứng trên bộ chuẩn đối sánh CAL-BENCH-001 (phiên bản 1.2.0) với 139 trường hợp kiểm thử biên, đạt kết quả trùng khớp hoàn toàn với dữ liệu thực nghiệm tiêu chuẩn.  
**Conclusion:** Phương pháp này được phê chuẩn làm quy chuẩn source of truth chuẩn mực cho thư viện `@quizzman/qm-calendar` và các dịch vụ tính lịch thuộc hệ sinh thái Quizzman.

---

## 1 Scope

Tài liệu này quy định phương pháp toán học và quy tắc thuật toán chuẩn để:
1. Xác định thời điểm bắt đầu và kết thúc của một ngày dân sự (civil day) trong thang đo thời gian địa phương.
2. Quy đổi mốc thời gian Unix (tính bằng milliseconds UTC) sang ngày dân sự số nguyên.
3. Thiết lập giao diện chuẩn giữa tầng tính toán chuyển động thiên văn (astronomical ephemeris) và tầng biểu diễn lịch pháp dân sự.

Phạm vi áp dụng bao gồm toàn bộ các động cơ tính toán trong hệ thống Quizzman, đặc biệt là các module đồng bộ lịch âm dương Việt Nam (múi giờ chuẩn UTC+07:00) và quốc tế.

## 2 Normative references

Các tài liệu viện dẫn sau đây là không thể thiếu cho việc áp dụng phương pháp này:

- **ISO 8601-1:2019** [@REF-ISO-8601], *Date and time — Representations for information interchange — Part 1: Basic rules*.
- **Jean Meeus (1998)** [@REF-MEEUS-1998], *Astronomical Algorithms*, 2nd Edition, Willmann-Bell.
- **E. M. Standish (1998)** [@REF-STANDISH-1998], *JPL Planetary and Lunar Ephemerides*, DE405/LE405.
- **Quizzman Calendar Engine Specification** [@REF-QM-CAL-2026], *Quizzman Lunisolar Engine Core Specification*.
- **Hồ Ngọc Đức (2000)** [@REF-HO-2000], *Lunisolar Calendar Calculations and Vietnamese Standard Meridian*.

## 3 Terms and definitions

Trong khuôn khổ tài liệu này, các thuật ngữ và định nghĩa sau đây được áp dụng:

### 3.1 civil day
Khoảng thời gian liên tục kéo dài chính xác 86 400 giây mặt trời quy ước (hoặc độ dài tương ứng sau khi điều chỉnh giây nhuận nếu có), bắt đầu từ thời khắc nửa đêm (00:00:00) và kết thúc tại thời khắc 24:00:00 của cùng ngày đó theo giờ địa phương.

### 3.2 midnight transition
Thời khắc phân định chuyển giao tức thời giữa hai ngày dân sự liên tiếp, tương ứng với $00:00:00.000$ giờ địa phương.

### 3.3 governing timezone offset
Độ lệch thời gian chuẩn tính bằng phút hoặc giây giữa giờ pháp định của vùng lãnh thổ áp dụng và Giờ Phối hợp Quốc tế (UTC).

## 4 Symbols and abbreviated terms

- **$T_{utc}$**: Dấu thời gian tính bằng milliseconds kể từ Unix Epoch (1970-01-01T00:00:00Z).
- **$Z$**: Độ lệch múi giờ quy chiếu tính bằng phút (ví dụ: $+420$ đối với UTC+07:00).
- **$T_{local}$**: Dấu thời gian địa phương tính bằng milliseconds sau khi áp dụng độ lệch $Z$.
- **$D_{civil}$**: Chỉ số ngày dân sự dạng số nguyên liên tục (Julian Day Number hoặc Days since Epoch).
- **$\Delta T$**: Hiệu số giữa Thời gian Nhiệt động lực học (TT) và Thời gian Quốc tế (UT1).

## 5 Conventions and assumptions

1. **Hệ quy chiếu thời gian:** Mọi dấu thời gian đầu vào ở tầng lõi phân tán của Quizzman SHALL được lưu trữ dưới dạng UTC.
2. **Kinh tuyến quy chiếu tiêu chuẩn:** Lịch âm dương truyền thống Việt Nam áp dụng kinh tuyến chuẩn $105^\circ$ Đông, tương ứng độ lệch múi giờ pháp định $Z = +420$ phút (xem thêm tài liệu [@REF-HO-2000]).
3. **Quy ước làm tròn:** Khi chuyển đổi thời gian liên tục sang ngày rời rạc, phép toán làm tròn xuống (`floor`) SHALL được sử dụng trên trục thời gian cục bộ.

## 6 Background

Lịch âm dương dựa trên hai hiện tượng thiên văn chính: thời điểm trăng mới (sóc) để định ngày mồng 1 đầu tháng, và thời điểm mặt trời đi qua các điểm phân/chí để định 24 tiết khí [@REF-MEEUS-1998]. Vì trăng mới xảy ra đồng thời trên toàn cầu theo thang đo thời gian tuyệt đối, ngày mồng 1 của một tháng âm lịch phụ thuộc hoàn toàn vào việc thời điểm sóc nằm trước hay sau thời khắc nửa đêm theo giờ dân sự của địa phương quan sát. Một sai số nhỏ trong việc xử lý ranh giới nửa đêm có thể dẫn đến việc lệch trọn một ngày của toàn bộ tháng âm lịch.

## 7 Sources and materials

Phương pháp quy chiếu này kế thừa các nguyên lý nền tảng từ:
1. Quy chuẩn biểu diễn ngày đêm quốc tế ISO 8601 [@REF-ISO-8601].
2. Bảng tham số khử chuyển động biểu kiến và thời gian Terrestrial Time từ JPL DE405 [@REF-STANDISH-1998].
3. Nghiên cứu kinh tuyến tính lịch âm Việt Nam của Hồ Ngọc Đức [@REF-HO-2000].

## 8 Methodology

Phương pháp tiếp cận bao gồm ba bước xử lý rời rạc:
1. Tiếp nhận dấu thời gian nguyên thủy $T_{utc}$ và định danh múi giờ quy chiếu.
2. Chiếu $T_{utc}$ lên trục thời gian địa phương thông qua hàm biến đổi tịnh tiến độ lệch tuyến tính $Z$.
3. Phân hoạch trục thời gian cục bộ thành các khoảng không giao nhau có độ dài chu kỳ $86\,400\,000 \text{ ms}$, với gốc tọa độ đặt tại nửa đêm ngày 1970-01-01.

## 9 Formal model

Cho $T_{utc} \in \mathbb{Z}$ là số mili-giây kể từ epoch UTC. Cho $Z \in [-720, 840]$ là độ lệch múi giờ tính bằng phút.

Thời gian cục bộ $T_{local}$ được xác định bởi:

$$T_{local} = T_{utc} + (Z \times 60\,000)$$

Chỉ số ngày dân sự liên tục $D_{civil}$ (số ngày kể từ 1970-01-01 cục bộ) được xác định thông qua hàm phần nguyên Gauss:

$$D_{civil} = \left\lfloor \frac{T_{local}}{86\,400\,000} \right\rfloor$$

Thời điểm nửa đêm bắt đầu ngày dân sự tương ứng với giá trị $T_{local}$ thỏa mãn:

$$T_{local} \pmod{86\,400\,000} = 0$$

## 10 Algorithm or rules

<!-- section_type: normative -->

### 10.1 Quy tắc R001: Chuyển giao nửa đêm (Civil Midnight Ingestion Rule)
- **Mã quy tắc:** `CAL-R001`
- **Tính chất:** Normative (Bắt buộc tuân thủ)
- **Tiền điều kiện:** 
  1. $T_{utc}$ là số nguyên hợp lệ biểu diễn milliseconds.
  2. $Z$ là số nguyên hợp lệ trong khoảng $[-720, 840]$.
- **Nội dung quy tắc:**
  Mọi hệ thống xử lý lịch của Quizzman **SHALL** xác định thời điểm bắt đầu của ngày dân sự mới tại thời khắc $T_{local} \equiv 0 \pmod{86\,400\,000}$.
  Nếu một sự kiện thiên văn (ví dụ: điểm Sóc) xảy ra tại $T_{local} = 86\,399\,999 \text{ ms}$, sự kiện đó **SHALL** được gán vào ngày $D_{civil}$. Nếu sự kiện xảy ra tại $T_{local} = 86\,400\,000 \text{ ms}$, sự kiện đó **SHALL** được gán vào ngày $D_{civil} + 1$.
- **Hành vi cấm:** Các triển khai phần mềm **SHALL NOT** sử dụng phương pháp xấp xỉ dấu phẩy động làm tròn thông thường (`Math.round`) để tránh sai số một mili-giây tại biên.

## 11 Implementation

Quy chuẩn này được hiện thực hóa trong gói mã nguồn chính thức `@quizzman/qm-calendar` [@REF-QM-CAL-2026], module `src/core/civil-day.ts`:

```typescript
export function getCivilDateFromTimestamp(
  utcTimestampMs: number,
  timezoneOffsetMinutes: number
): { civilDate: string; civilDayIndex: number } {
  const localMs = utcTimestampMs + timezoneOffsetMinutes * 60_000;
  const civilDayIndex = Math.floor(localMs / 86_400_000);
  const localDate = new Date(localMs);
  
  const year = localDate.getUTCFullYear();
  const month = String(localDate.getUTCMonth() + 1).padStart(2, '0');
  const day = String(localDate.getUTCDate()).padStart(2, '0');
  
  return {
    civilDate: `${year}-${month}-${day}`,
    civilDayIndex
  };
}
```

## 12 Validation

Tính đúng đắn của phương pháp được thẩm định thông qua quy trình kiểm thử tự động trên bộ dữ liệu `CAL-BENCH-001` (phiên bản 1.2.0), bao gồm:
1. 100 mốc thời gian ngẫu nhiên trải dài từ năm 1900 đến 2100.
2. 39 mốc thời gian biên nhạy cảm: các thời điểm $23:59:59.999$, $00:00:00.000$, và $00:00:00.001$ vào các ngày chuyển giao tháng và năm nhuận.

## 13 Results

Trong đợt thử nghiệm đối sánh chính thức với bộ véc-tơ kiểm chuẩn `CAL-BENCH-001`:
- **Tổng số véc-tơ đánh giá:** 139 / 139 trường hợp.
- **Số lượng trùng khớp tuyệt đối:** 139 / 139 trường hợp (100% véc-tơ trong bộ kiểm chuẩn).
- **Số lượng bất đồng (discrepancies):** 0 trường hợp.
- **Thời gian thực thi trung bình:** 0.0002 ms / thao tác chuyển đổi trên môi trường Node.js 20.x.

## 14 Discussion

Kết quả kiểm nghiệm khẳng định tính ổn định số học của hàm sàn số nguyên (`floor`). Việc tách biệt rõ ràng giữa độ lệch múi giờ pháp định $Z$ và thời gian UTC thuần túy giúp loại bỏ các hiệu ứng lề do Daylight Saving Time (DST) gây ra, bảo đảm tính xác định tuyệt đối (determinism) cần thiết cho việc đồng bộ trạng thái hệ thống phân tán.

## 15 Limitations

Phương pháp này có các giới hạn kỹ thuật được ghi nhận sau đây:
1. **Phạm vi biểu diễn thời gian:** Thuật toán dựa trên kiểu số nguyên 64-bit IEEE 754 float trong JavaScript (giá trị an toàn từ $-8\,640\,000\,000\,000\,000 \text{ ms}$ đến $+8\,640\,000\,000\,000\,000 \text{ ms}$, tương ứng khoảng năm $-271821$ đến $+275760$). Ngoài phạm vi này, sai số biểu diễn có thể xảy ra.
2. **Biến động lịch sử của múi giờ:** Phương pháp giả định độ lệch $Z$ là hằng số đã biết tại thời điểm tra cứu. Đối với các mốc thời gian lịch sử trước thế kỷ 20, khi múi giờ địa phương chưa được tiêu chuẩn hóa theo quy chuẩn quốc tế, cần tham chiếu bảng chuyển đổi bổ sung thay vì một hằng số $Z$.
3. **Giới hạn kiểm nghiệm:** Việc vượt qua 139 trường hợp kiểm thử trong bộ dữ liệu `CAL-BENCH-001` chứng minh tính nhất quán trong miền kiểm chuẩn đã định, nhưng không đại diện cho toàn bộ các trường hợp chuyển đổi múi giờ có quy định pháp lý dị biệt tại các vùng lãnh thổ đặc thù.

## 16 Conclusion

Phương pháp quy chiếu xác định ranh giới ngày dân sự `QP-EXAMPLE-001` đã chứng minh tính chặt chẽ về toán học và sự tương thích hoàn toàn với các tiêu chuẩn quốc tế ISO 8601. Tài liệu này được ban hành làm chuẩn mực quy chiếu chính thức cấp độ `stable` cho toàn bộ các ứng dụng thuộc hệ sinh thái Quizzman.

## Bibliography

[1] International Organization for Standardization. ISO 8601-1:2019 Date and time — Representations for information interchange. Geneva: ISO, 2019.  
[2] Jean Meeus. Astronomical Algorithms. 2nd edition. Richmond: Willmann-Bell, 1998.  
[3] E. Myles Standish. JPL Planetary and Lunar Ephemerides, DE405/LE405. JPL IOM 312.F, 1998.  
[4] Quizzman Research & Engineering. Quizzman Calendar Engine Specification. Version 2.1.0, 2026.  
[5] Hồ Ngọc Đức. Lunisolar Calendar Calculations and Vietnamese Standard Meridian. Leipzig University, 2000.  

## Annex A — Algorithms (Normative)

Triển khai quy chuẩn cho thuật toán tính toán ranh giới ngày và phân bổ chỉ số thời gian:

```typescript
export interface CivilDayResult {
  readonly timestampLocalMs: number;
  readonly civilDayIndex: number;
  readonly isExactMidnight: boolean;
}

export function evaluateCivilBoundary(
  utcMs: number,
  offsetMinutes: number
): CivilDayResult {
  const timestampLocalMs = utcMs + offsetMinutes * 60_000;
  const civilDayIndex = Math.floor(timestampLocalMs / 86_400_000);
  const remainder = ((timestampLocalMs % 86_400_000) + 86_400_000) % 86_400_000;
  
  return {
    timestampLocalMs,
    civilDayIndex,
    isExactMidnight: remainder === 0
  };
}
```

## Annex B — Test vectors (Informative)

Bảng các véc-tơ kiểm thử mẫu trích xuất từ `CAL-BENCH-001` (xem chi tiết tại tệp `artifacts/test-vectors.json`):

| Test ID | UTC ISO Timestamp | Múi giờ ($Z$) | Local ISO Timestamp | Ngày dân sự dự kiến | Kết quả |
|---|---|---|---|---|---|
| CAL-R001-T01 | `2026-09-30T23:59:59.000Z` | +420 (VN) | `2026-10-01T06:59:59.000+07:00` | 2026-10-01 | PASS |
| CAL-R001-T02 | `2026-09-30T07:59:59.999Z` | +420 (VN) | `2026-09-30T14:59:59.999+07:00` | 2026-09-30 | PASS |
| CAL-R001-T03 | `2026-10-01T01:00:00.000Z` | +420 (VN) | `2026-10-01T08:00:00.000+07:00` | 2026-10-01 | PASS |
