新婚蜜月行程规划
刚结婚的小林和妻子计划去海边度假一周,两人不想在旅途中被意外打乱节奏。妻子经期一向规律,周期 28 天,末次月经刚好在出发前 3 天结束。她用本工具输入日期和周期长度,算出未来 7 天均为安全期,确认整个蜜月行程无需额外准备,两人安心订好了浮潜和登山项目。
凌晨一点,手机备忘录上记着上次经期第一天,翻日历算安全期却总怕算错——差一天,结果可能完全不同。输入经期首日和平均周期长度,工具直接标出安全期、排卵期和月经期,不依赖任何云端计算。数据只在浏览器里处理,关掉页面即消失。适合不想装 App、也不愿把生理数据交给第三方的人,睡前随手一填,看一眼就睡。
刚结婚的小林和妻子计划去海边度假一周,两人不想在旅途中被意外打乱节奏。妻子经期一向规律,周期 28 天,末次月经刚好在出发前 3 天结束。她用本工具输入日期和周期长度,算出未来 7 天均为安全期,确认整个蜜月行程无需额外准备,两人安心订好了浮潜和登山项目。
异地恋情侣小陈和女友每月只能见一次,每次见面都提前算好日子。女友周期 32 天,上月 5 号来月经,这月预计 6 号。小陈用本工具输入上个月经开始日和周期长度,算出 20 号到 25 号是安全期,果断买了 22 号的票,避免了见面时因不确定而产生的焦虑和临时改签费用。
备孕半年的阿玲和老公想提高命中率,但排卵试纸总记错时间。她周期 30 天,上月 10 号来月经。用本工具输入日期和周期,工具自动标出排卵期窗口(下次月经前 14 天左右),她发现 24 号到 28 号为易孕期,两人据此安排了同房频率,不再靠感觉盲目尝试。
周五晚上室友临时提议去露营,小周正好在经期第 4 天,不确定周末能不能下水。她掏出手机用本工具输入本次经期开始日和 28 天周期,算出周六周日都在安全期内,且经血量已减少,放心收拾睡袋加入。避免了因信息不足而扫兴或硬撑的尴尬。
销售总监王姐下周要飞深圳参加三天展会,但月经预计正好撞期。她周期 26 天,末次月经 1 号,用本工具输入后看到展会那几天(8-10 号)恰好是经期第 8-10 天,属于安全期,但经期可能还没完全结束。她据此提前准备了卫生用品和止痛药,并调整了第一天的高强度演讲安排,避免了现场手忙脚乱。
| 维度 | 本工具 | 经期记录 App | 传统日历法 |
|---|---|---|---|
| 隐私 | 纯浏览器计算,数据不上传服务器 | 需注册账号,数据存储于云端 | 完全离线,无电子记录 |
| 离线可用 | 页面加载后断网仍可计算 | 多数需联网同步 | 始终可用 |
| 操作步骤 | 输入经期日期与周期长度,一键出结果 | 需持续记录多个月经周期才能预测 | 手工标记日历,自行推算 |
| 数据依赖 | 仅需最近一次经期与平均周期 | 依赖历史记录完整性 | 依赖个人记忆与标记习惯 |
| 结果精度 | 基于固定周期假设,周期不规律时误差增大 | 算法可结合历史波动,相对更准 | 完全依赖个人推算,易出错 |
| 输入 | 输出 | 说明 |
|---|---|---|
| 经期 5 天,周期 28 天,上次月经第一天 2026-03-01 | 安全期:月经期 03-01 至 03-05,排卵期 03-12 至 03-16,安全期(排卵前)03-06 至 03-11,安全期(排卵后)03-17 至 03-28 | 常规:标准 28 天周期,输出清晰展示月经期、排卵期、两个安全期段,验证基础逻辑 |
| 经期 7 天,周期 35 天,上次月经第一天 2026-04-10 | 安全期:月经期 04-10 至 04-16,排卵期 04-24 至 04-28,安全期(排卵前)04-17 至 04-23,安全期(排卵后)04-29 至 05-14 | 常规:长周期(35 天),验证排卵日计算(周期 - 14)在长周期下的正确性 |
| 经期 3 天,周期 21 天,上次月经第一天 2026-05-01 | 安全期:月经期 05-01 至 05-03,排卵期 05-08 至 05-12,安全期(排卵前)05-04 至 05-07,安全期(排卵后)05-13 至 05-21 | 边界:极短周期(21 天),排卵日接近月经结束,验证安全期窗口是否合理 |
| 经期 10 天,周期 40 天,上次月经第一天 2026-06-15 | 安全期:月经期 06-15 至 06-24,排卵期 07-01 至 07-05,安全期(排卵前)06-25 至 06-30,安全期(排卵后)07-06 至 07-24 | 边界:超长周期(40 天)且经期长达 10 天,验证工具能否正确处理经期与排卵期的间隔 |
| 经期 1 天,周期 28 天,上次月经第一天 2026-07-01 | 安全期:月经期 07-01 至 07-01,排卵期 07-12 至 07-16,安全期(排卵前)07-02 至 07-11,安全期(排卵后)07-17 至 07-28 | 边界:经期仅 1 天,验证工具是否接受极端短经期,输出是否正常 |
| 经期 5 天,周期 28 天,上次月经第一天 2026-02-28(闰年) | 安全期:月经期 02-28 至 03-04,排卵期 03-11 至 03-15,安全期(排卵前)03-05 至 03-10,安全期(排卵后)03-16 至 03-27 | 易错:闰年 2 月 28 日输入,跨月日期计算容易出错,验证工具对闰年跨月场景的处理 |
| 经期 5 天,周期 28 天,上次月经第一天 2026-12-28 | 安全期:月经期 12-28 至 01-01,排卵期 01-08 至 01-12,安全期(排卵前)01-02 至 01-07,安全期(排卵后)01-13 至 01-24 | 易错:年末跨年输入,输出日期跨到次年,验证工具能否正确处理年份边界 |
1.将安全期等同于绝对安全
在安全期内不采取任何避孕措施安全期内仍建议使用避孕套等屏障避孕法安全期计算基于平均周期统计,个体排卵可能因压力、疾病等提前或推迟,实际失败率约 2-20%,非 100% 可靠。
2.周期长度输入错误:用单次周期代替平均周期
上次周期 28 天,这次也输入 28输入过去 6-12 个月的平均周期长度(如 29.5)单次周期受临时因素影响大,工具假设周期规律性,用单次值计算会放大误差。
3.经期首日判断错误:将经期结束日当作首日
月经 5 天,从第 3 天开始算第一天月经第一天是出血第一天(哪怕只有少量血迹)安全期算法以出血首日为周期起点,错位一天会导致整个日历偏移,排卵日推算错误。
4.忽略周期不规律对结果的影响
周期 25-35 天波动,仍用单次 28 天计算周期波动 >7 天时,安全期结果仅供参考,不宜作为唯一避孕依据安全期计算依赖周期规律性,波动越大,排卵日预测窗口越宽,安全期实际长度缩短甚至消失。
5.将安全期结果用于备孕时误解窗口期
安全期显示易孕期,以为这几天都能受孕易孕期指排卵日前 5 天 + 排卵日,共约 6 天卵子存活约 24 小时,精子存活约 5 天,真正受孕窗口是排卵日前 5 天至排卵后 1 天,不是整个易孕期。
安全期 = 排卵日前5天 + 排卵日 + 排卵日后4天(危险期);其余为安全期
周期长度两次月经第一天间隔天数经期长度每次出血持续天数排卵日周期长度 − 14(假设黄体期固定14天)周期长度 28 天、经期长度 5 天:排卵日 = 28 − 14 = 第14天;危险期 = 第9天至第18天(14−5 到 14+4);安全期 = 第1–8天(经期后至危险期前)和第19–28天(危险期后至下次月经前)。
5 种主流语言实现,复制即用:
from datetime import datetime, timedelta
def safe_period(last_period_start: str, cycle_length: int) -> dict:
"""
计算安全期(排卵前安全期 + 排卵后安全期)
假设排卵日在周期第14天,卵子存活24h,精子存活72h
"""
start = datetime.strptime(last_period_start, '%Y-%m-%d')
ovulation_day = start + timedelta(days=cycle_length - 14)
# 易孕期:排卵前3天到排卵后1天
fertile_start = ovulation_day - timedelta(days=3)
fertile_end = ovulation_day + timedelta(days=1)
# 安全期 = 周期中除易孕期外的部分
next_period = start + timedelta(days=cycle_length)
return {
"排卵前安全期": f"{start.date()} ~ {(fertile_start - timedelta(days=1)).date()}",
"易孕期": f"{fertile_start.date()} ~ {fertile_end.date()}",
"排卵后安全期": f"{(fertile_end + timedelta(days=1)).date()} ~ {(next_period - timedelta(days=1)).date()}"
}
# 示例:上次月经2025-01-01,周期28天
print(safe_period('2025-01-01', 28))
# 输出: {'排卵前安全期': '2025-01-01 ~ 2025-01-10', '易孕期': '2025-01-11 ~ 2025-01-15', '排卵后安全期': '2025-01-16 ~ 2025-01-27'}/**
* 计算安全期(基于日历法,周期28天为例)
* @param {string} lastPeriodStart - 上次月经开始日期 'YYYY-MM-DD'
* @param {number} cycleLength - 月经周期天数
* @returns {object} 安全期与易孕期范围
*/
function safePeriod(lastPeriodStart, cycleLength = 28) {
const start = new Date(lastPeriodStart);
const ovulationDay = new Date(start);
ovulationDay.setDate(start.getDate() + cycleLength - 14); // 排卵日
const fertileStart = new Date(ovulationDay);
fertileStart.setDate(ovulationDay.getDate() - 3); // 精子存活72h
const fertileEnd = new Date(ovulationDay);
fertileEnd.setDate(ovulationDay.getDate() + 1); // 卵子存活24h
const nextPeriod = new Date(start);
nextPeriod.setDate(start.getDate() + cycleLength);
const fmt = d => d.toISOString().split('T')[0];
return {
preOvulationSafe: `${fmt(start)} ~ ${fmt(new Date(fertileStart.getTime() - 86400000))}`,
fertileWindow: `${fmt(fertileStart)} ~ ${fmt(fertileEnd)}`,
postOvulationSafe: `${fmt(new Date(fertileEnd.getTime() + 86400000))} ~ ${fmt(new Date(nextPeriod.getTime() - 86400000))}`
};
}
console.log(safePeriod('2025-01-01', 28));
// 输出: { preOvulationSafe: '2025-01-01 ~ 2025-01-10', fertileWindow: '2025-01-11 ~ 2025-01-15', postOvulationSafe: '2025-01-16 ~ 2025-01-27' }package main
import (
"fmt"
"time"
)
// SafePeriod 计算安全期范围
func SafePeriod(lastStart string, cycleLen int) (map[string]string, error) {
start, err := time.Parse("2006-01-02", lastStart)
if err != nil {
return nil, err
}
ovulationDay := start.AddDate(0, 0, cycleLen-14) // 排卵日
fertileStart := ovulationDay.AddDate(0, 0, -3) // 精子存活72h
fertileEnd := ovulationDay.AddDate(0, 0, 1) // 卵子存活24h
nextPeriod := start.AddDate(0, 0, cycleLen)
return map[string]string{
"排卵前安全期": fmt.Sprintf("%s ~ %s", start.Format("2006-01-02"), fertileStart.AddDate(0, 0, -1).Format("2006-01-02")),
"易孕期": fmt.Sprintf("%s ~ %s", fertileStart.Format("2006-01-02"), fertileEnd.Format("2006-01-02")),
"排卵后安全期": fmt.Sprintf("%s ~ %s", fertileEnd.AddDate(0, 0, 1).Format("2006-01-02"), nextPeriod.AddDate(0, 0, -1).Format("2006-01-02")),
}, nil
}
func main() {
result, err := SafePeriod("2025-01-01", 28)
if err != nil {
fmt.Println("输入日期格式错误")
return
}
for k, v := range result {
fmt.Printf("%s: %s\n", k, v)
}
// 输出: 排卵前安全期: 2025-01-01 ~ 2025-01-10
// 易孕期: 2025-01-11 ~ 2025-01-15
// 排卵后安全期: 2025-01-16 ~ 2025-01-27
}interface SafePeriodResult {
preOvulationSafe: string;
fertileWindow: string;
postOvulationSafe: string;
}
function safePeriod(lastPeriodStart: string, cycleLength: number = 28): SafePeriodResult {
const start = new Date(lastPeriodStart);
const ovulationDay = new Date(start);
ovulationDay.setDate(start.getDate() + cycleLength - 14);
const fertileStart = new Date(ovulationDay);
fertileStart.setDate(ovulationDay.getDate() - 3);
const fertileEnd = new Date(ovulationDay);
fertileEnd.setDate(ovulationDay.getDate() + 1);
const nextPeriod = new Date(start);
nextPeriod.setDate(start.getDate() + cycleLength);
const fmt = (d: Date) => d.toISOString().split('T')[0];
return {
preOvulationSafe: `${fmt(start)} ~ ${fmt(new Date(fertileStart.getTime() - 86400000))}`,
fertileWindow: `${fmt(fertileStart)} ~ ${fmt(fertileEnd)}`,
postOvulationSafe: `${fmt(new Date(fertileEnd.getTime() + 86400000))} ~ ${fmt(new Date(nextPeriod.getTime() - 86400000))}`
};
}
console.log(safePeriod('2025-01-01', 28));
// 输出: { preOvulationSafe: '2025-01-01 ~ 2025-01-10', fertileWindow: '2025-01-11 ~ 2025-01-15', postOvulationSafe: '2025-01-16 ~ 2025-01-27' }use chrono::{NaiveDate, Duration};
fn safe_period(last_start: &str, cycle_len: i64) -> Result<(), Box<dyn std::error::Error>> {
let start = NaiveDate::parse_from_str(last_start, "%Y-%m-%d")?;
let ovulation = start + Duration::days(cycle_len - 14);
let fertile_start = ovulation - Duration::days(3);
let fertile_end = ovulation + Duration::days(1);
let next_period = start + Duration::days(cycle_len);
println!("排卵前安全期: {} ~ {}", start, fertile_start - Duration::days(1));
println!("易孕期: {} ~ {}", fertile_start, fertile_end);
println!("排卵后安全期: {} ~ {}", fertile_end + Duration::days(1), next_period - Duration::days(1));
Ok(())
}
fn main() {
safe_period("2025-01-01", 28).unwrap();
// 输出:
// 排卵前安全期: 2025-01-01 ~ 2025-01-10
// 易孕期: 2025-01-11 ~ 2025-01-15
// 排卵后安全期: 2025-01-16 ~ 2025-01-27
}输入最近一次月经第一天(日期)和平均周期长度(比如 28 天)。工具会基于标准日历法推算:排卵日 ≈ 周期长度 − 14 天,排卵期前后共约 8 天(排卵前 5 天 + 后 3 天)为易孕期,其余为安全期。结果会标出每个阶段的起止日期。注意:周期长度按最近 6-12 个月的平均值算更准,单次输入偏差大结果可能不准。
可以输入,但结果参考价值有限。日历法依赖周期规律性——周期波动 ≤ 3 天时准确率较高;波动 ≥ 7 天时排卵日预测误差可达数天,安全期窗口会缩小甚至消失。工具会在结果旁标注「周期波动较大,建议结合排卵试纸或基础体温」。如果周期完全没规律(如多囊),不建议单独依赖此工具。
不同工具用的算法版本不同。本工具采用标准日历法(排卵日 = 周期 − 14),部分 App 用改良版(如减去 12-16 天取范围),也有用统计模型(基于大量用户数据推算概率)。另外输入参数不同也会导致差异——比如周期长度取的是平均值还是中位数。结果差 1-2 天正常,差 3 天以上建议检查输入是否一致。
不是。日历法安全期避孕的失败率约 20-25%(典型使用),远高于避孕套(约 13%)或短效避孕药(约 7%)。原因是排卵可能提前或推迟——压力、生病、熬夜、旅行都会影响激素。工具结果基于统计规律,不保证个体 100% 准确。工具页面有风险提示,建议仅作为参考,不要单独作为避孕依据。
结果会明确标出三个区间:月经期(第 1-5 天左右)、安全期(月经干净后到排卵期前 + 排卵后到下次月经前)、易孕期(排卵前 5 天到排卵后 3 天)。具体日期按你输入的周期长度自动计算。例如周期 28 天,排卵日 ≈ 第 14 天,易孕期 ≈ 第 9-17 天,其余为安全期。注意结果会精确到具体日期。
不用联网。本工具纯前端运行(FE),所有计算在浏览器本地完成,不向服务器发送任何数据。刷新或关闭页面后输入内容不会保留。如果担心隐私,可以断网使用——页面加载后断网,工具照常算。无登录要求,无数据存储,无第三方统计。
直接修改输入框里的日期或周期长度,结果会实时刷新。没有「重置」按钮——改输入框的值就是重置。如果发现结果不对,先检查:① 月经第一天是否选了正确日期(不是结束日);② 周期长度是否填了整数(不支持小数,比如 28.5 天会报错)。工具不接受非数字字符。
安全期是「不易怀孕」的时间段,排卵期是「最容易怀孕」的时间段。排卵期通常指排卵日前后共 6 天(精子存活 5 天 + 卵子存活 1 天),安全期则是除月经期和排卵期之外的日子。工具结果会同时标出这两个区间。注意:安全期≠绝对安全,排卵期≠一定怀孕——只是概率高低。
周期越长,排卵日越靠后(32 天周期排卵日 ≈ 第 18 天),但易孕期仍是排卵前 5 天到后 3 天(约第 13-21 天)。月经期约 5 天,加上易孕期 9 天,剩余安全期确实可能只有 6-8 天。如果周期不规律,安全期窗口会更窄。工具算法对所有周期长度一视同仁,不因结果「不理想」而调整。
隐私保证所有计算与处理均在你的浏览器本地完成,输入数据不会上传服务器,也不会保存或共享。