世界杯开幕了,手把手教你做个看球小工具

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: 先把数据结构化,再用程序处理确定性的查询和计算。这样做出来的工具,功能不一定复杂,但结果会更可靠。世界杯只是一个入口,真正值得练的是这种处理数据和时间的基本思路。

世界杯开幕了。

可能大家会第一时间关心几个很具体的问题:今天有什么比赛?下一场小组赛几点开始?换成北京时间是几点?我关注的球队后面还有哪几场?

这些问题当然可以直接去 FIFA 官网、体育 App 或搜索引擎里查。目前,现有工具已经能解决大部分需求了。

这次我们不打算重新造一个“世界杯赛程 App”,而是借这个足够轻、足够具体的场景,做一个可以跑起来的小工具:用 JSON 存赛程,用 Python 查询球队和日期,再把比赛所在地时间转换成北京时间和美东时间。

这个小工具不复杂,但它能练到几个很实用的点:结构化数据怎么设计、命令行参数怎么接、跨时区时间怎么换算,以及为什么“按日期查比赛”这件事在世界杯这种跨时区场景里并不简单。

需求分析

我们要做的这个世界杯看球小助手,需求看起来很简单:

帮我查一下墨西哥队的小组赛,转成北京时间,再告诉我哪天能看。

但真写起来会发现,最容易出问题的地方其实是时间。

一场比赛在举办地可能是 6 月 18 日,换成北京时间后已经是 6 月 19 日。如果我们只按比赛当地日期查询,国内读者输入“6 月 19 日有什么比赛”时,反而可能查不到自己那天真正能看的比赛。

所以这个小工具要解决三件事:

  1. 用结构化数据保存比赛信息,包括日期、时间、时区、球队和场馆;

  2. 支持按球队查询,比如查出墨西哥队全部 A 组小组赛;

  3. 支持按北京时间日期查询,比如查“北京时间 6 月 19 日有哪些比赛”。

最后做出来的流程大概是这样:

用户输入球队或日期
    ↓
程序读取本地赛程数据
    ↓
程序筛选对应比赛
    ↓
程序完成时区换算
    ↓
输出当地时间、北京时间和美东时间

这样我们就把“查询”和“时间换算”都放在程序里处理,结果更稳定,也更容易检查。

项目结构

下面,我们来完整做一下这个小工具。

先新建一个项目文件夹,名字叫 worldcup-helper。你可以在电脑上手动新建,也可以在终端执行:

mkdir worldcup-helper

然后打开 VS Code,选择「文件」→「打开文件夹」,选中刚刚创建的 worldcup-helper 文件夹。

打开后,在项目里新建两个文件:

worldcup-helper/
├── matches.json
└── worldcup_helper.py

其中:

  • matches.json:存放比赛数据

  • worldcup_helper.py:读取数据、查询比赛、转换时区,并输出结果

第一版先不接数据库,也不做复杂页面。我们只用一份本地 JSON 数据,把整个流程跑通。

Mock 数据

接下来先打开 matches.json,把下面这份示例数据写进去:

[
  {
    "id": "match_001",
    "match_no": 1,
    "date": "2026-06-11",
    "time": "13:00",
    "timezone": "America/Mexico_City",
    "team_a": "Mexico",
    "team_b": "South Africa",
    "stage": "First Stage",
    "group": "Group A",
    "venue": "Mexico City Stadium",
    "city": "Mexico City",
    "source": "FIFA"
  }
]

这里我们先用本届世界杯的第一场比赛,也就是墨西哥 vs 南非这场 Group A 小组赛,作为示例数据。

这份数据里,最关键的是三个字段:

"date": "2026-06-11",
"time": "13:00",
"timezone": "America/Mexico_City"

这三个字段最好一开始就写清楚。很多时区换算、跨天显示的问题,往往都是因为一开始只写了时间,却没有写清楚它属于哪个时区。如果只存一个字符串,比如“6 月 11 日下午 1 点”,后面就很难判断这是哪个城市的下午 1 点,也很难可靠地转成北京时间、美东时间或其他时区。

所以我们尽量把数据拆清楚:

  • date:当地日期

  • time:当地开球时间

  • timezone:比赛所在时区

  • team_a / team_b:对阵双方

  • venue / city:比赛地点

这样后面的程序才能稳定处理查询和换算。

编写查询脚本

接下来,打开刚才创建好的 worldcup_helper.py

在第一版,这个脚本文件只做三件事:

  1. 读取 matches.json

  2. 按球队查询比赛

  3. 把比赛时间转成北京时间和美东时间

下面把这段代码写入 worldcup_helper.py

from datetime import datetime
from pathlib import Path
from zoneinfo import ZoneInfo
import json


BASE_DIR = Path(__file__).resolve().parent
MATCHES_FILE = BASE_DIR / "matches.json"


def load_matches(path=MATCHES_FILE):
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)


def match_time(match):
    source_tz = ZoneInfo(match["timezone"])

    local_time = datetime.fromisoformat(
        f'{match["date"]}T{match["time"]}'
    )

    return local_time.replace(tzinfo=source_tz)


def convert_time(match, target_timezone):
    return match_time(match).astimezone(ZoneInfo(target_timezone))


def find_by_team(matches, team_name):
    team_name = team_name.lower()

    return [
        match for match in matches
        if team_name in match["team_a"].lower()
        or team_name in match["team_b"].lower()
    ]


def format_match(match):
    beijing_time = convert_time(match, "Asia/Shanghai")
    eastern_time = convert_time(match, "America/New_York")

    return f"""
比赛:{match["team_a"]} vs {match["team_b"]}
阶段:{match["stage"]} / {match["group"]}
地点:{match["venue"]}, {match["city"]}

当地时间:{match["date"]} {match["time"]} ({match["timezone"]})
北京时间:{beijing_time.strftime("%Y-%m-%d %H:%M")}
美东时间:{eastern_time.strftime("%Y-%m-%d %H:%M")}
""".strip()


if __name__ == "__main__":
    matches = load_matches()
    results = find_by_team(matches, "Mexico")

    if not results:
        print("没有找到相关比赛")
    else:
        print(format_match(results[0]))

这段代码里,最关键的是 match_time()convert_time() 这两个函数。

先看 match_time()。JSON 里存的是拆开的 datetimetimezone,程序需要先把它们组合成一个真正可计算的时间对象。这里的 datetime.fromisoformat() 会把 2026-06-1113:00 拼成 Python 能识别的时间;后面的 replace(tzinfo=source_tz) 则是给这个时间补上时区信息。

也就是说,2026-06-11 13:00 这串时间本身是不完整的。只有配上 America/Mexico_City,程序才知道它指的是墨西哥城当地时间,而不是北京时间或美东时间。

接着看 convert_time()。这里没有手动写“墨西哥时间 +14 小时 = 北京时间”,而是调用 astimezone(),把这个带时区的时间转换到目标时区。因为时区换算不只是简单加减几个小时,还可能涉及日期跨天、夏令时、不同城市的时区规则等问题。只要把源时区和目标时区写清楚,剩下的换算交给 Python 处理。

此外,还有一个小细节需要我们留意下:

BASE_DIR = Path(__file__).resolve().parent
MATCHES_FILE = BASE_DIR / "matches.json"

这两行是为了让脚本始终读取自己所在目录下的 matches.json。这样即使你不是在项目目录里运行脚本,也不容易因为路径问题找不到数据文件。

运行第一版

保存 matches.jsonworldcup_helper.py 后,在终端里进入项目目录:

cd worldcup-helper

然后运行:

python3 worldcup_helper.py

你会看到类似输出:

比赛:Mexico vs South Africa
阶段:First Stage / Group A
地点:Mexico City Stadium, Mexico City

当地时间:2026-06-11 13:00 (America/Mexico_City)
北京时间:2026-06-12 03:00
美东时间:2026-06-11 15:00

实操参考图

到这里,第一版已经跑通了。

这一版先用程序完成读取数据、查询比赛和时区换算。这样做的好处是,比赛时间、时区换算、跨天显示这些信息,都放在可控的程序逻辑里处理,结果更稳定,也更容易检查。

加一点命令行能力

现在 worldcup_helper.py 里写死了查询 Mexico,只执行 python3 worldcup_helper.py。即使我们在命令后面追加了球队参数,命令依旧会执行查询 Mexico。像是这样

我来试试给它增加点参数支持,我们的目标是支持按球队查询:

python3 worldcup_helper.py --team Mexico

也支持按北京时间日期查询:

python3 worldcup_helper.py --date 2026-06-19

现在,把 worldcup_helper.py 里的内容替换成下面这样:

from datetime import datetime
from pathlib import Path
from zoneinfo import ZoneInfo
import argparse
import json


BASE_DIR = Path(__file__).resolve().parent
MATCHES_FILE = BASE_DIR / "matches.json"


def load_matches(path=MATCHES_FILE):
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)


def match_time(match):
    source_tz = ZoneInfo(match["timezone"])

    local_time = datetime.fromisoformat(
        f'{match["date"]}T{match["time"]}'
    )

    return local_time.replace(tzinfo=source_tz)


def convert_time(match, target_timezone):
    return match_time(match).astimezone(ZoneInfo(target_timezone))


def find_by_team(matches, team_name):
    team_name = team_name.lower()

    return [
        match for match in matches
        if team_name in match["team_a"].lower()
        or team_name in match["team_b"].lower()
    ]


def find_by_date(matches, date, target_timezone="Asia/Shanghai"):
    return [
        match for match in matches
        if convert_time(match, target_timezone).strftime("%Y-%m-%d") == date
    ]


def format_match(match):
    beijing_time = convert_time(match, "Asia/Shanghai")
    eastern_time = convert_time(match, "America/New_York")

    return f"""
比赛:{match["team_a"]} vs {match["team_b"]}
阶段:{match["stage"]} / {match["group"]}
地点:{match["venue"]}, {match["city"]}

当地时间:{match["date"]} {match["time"]} ({match["timezone"]})
北京时间:{beijing_time.strftime("%Y-%m-%d %H:%M")}
美东时间:{eastern_time.strftime("%Y-%m-%d %H:%M")}
""".strip()


def main():
    parser = argparse.ArgumentParser(description="世界杯赛程小助手")
    parser.add_argument("--team", help="按球队查询,比如 Mexico")
    parser.add_argument("--date", help="按北京时间日期查询,比如 2026-06-19")

    args = parser.parse_args()
    matches = load_matches()

    if args.team:
        results = find_by_team(matches, args.team)
    elif args.date:
        results = find_by_date(matches, args.date)
    else:
        results = matches

    if not results:
        print("没有找到相关比赛")
        return

    for match in results:
        print(format_match(match))
        print("-" * 40)


if __name__ == "__main__":
    main()

这里的关键点是:我们不是直接拿 JSON 里的 date 去比较。

JSON 里的 date 是比赛举办地日期,但用户输入的 --date,我们希望它代表北京时间日期。所以程序会先把每场比赛转成北京时间,再取出转换后的日期,和用户输入的日期做比较。

这样一来,举办地时间 2026-06-18 19:00 的比赛,如果换成北京时间是 2026-06-19 09:00,就会被归到北京时间 2026-06-19 这一天。

既然现在我们已经支持了查询球队和时间,那就往球赛的 json 文件中再添加本小组赛(A 组)的所有比赛,来看下效果:

[
  {
    "id": "match_001",
    "match_no": 1,
    "date": "2026-06-11",
    "time": "13:00",
    "timezone": "America/Mexico_City",
    "team_a": "Mexico",
    "team_b": "South Africa",
    "stage": "First Stage",
    "group": "Group A",
    "venue": "Mexico City Stadium",
    "city": "Mexico City",
    "source": "FIFA / MLS Soccer"
  },
  {
    "id": "match_002",
    "match_no": 2,
    "date": "2026-06-11",
    "time": "20:00",
    "timezone": "America/Mexico_City",
    "team_a": "Korea Republic",
    "team_b": "Czechia",
    "stage": "First Stage",
    "group": "Group A",
    "venue": "Estadio Guadalajara",
    "city": "Guadalajara",
    "source": "FIFA / MLS Soccer"
  },
  {
    "id": "match_003",
    "match_no": 3,
    "date": "2026-06-18",
    "time": "12:00",
    "timezone": "America/New_York",
    "team_a": "Czechia",
    "team_b": "South Africa",
    "stage": "First Stage",
    "group": "Group A",
    "venue": "Atlanta Stadium",
    "city": "Atlanta",
    "source": "FIFA / MLS Soccer"
  },
  {
    "id": "match_004",
    "match_no": 4,
    "date": "2026-06-18",
    "time": "19:00",
    "timezone": "America/Mexico_City",
    "team_a": "Mexico",
    "team_b": "Korea Republic",
    "stage": "First Stage",
    "group": "Group A",
    "venue": "Estadio Guadalajara",
    "city": "Guadalajara",
    "source": "FIFA / MLS Soccer"
  },
  {
    "id": "match_005",
    "match_no": 5,
    "date": "2026-06-24",
    "time": "19:00",
    "timezone": "America/Mexico_City",
    "team_a": "Czechia",
    "team_b": "Mexico",
    "stage": "First Stage",
    "group": "Group A",
    "venue": "Mexico City Stadium",
    "city": "Mexico City",
    "source": "FIFA / MLS Soccer"
  },
  {
    "id": "match_006",
    "match_no": 6,
    "date": "2026-06-24",
    "time": "19:00",
    "timezone": "America/Monterrey",
    "team_a": "South Africa",
    "team_b": "Korea Republic",
    "stage": "First Stage",
    "group": "Group A",
    "venue": "Estadio Monterrey",
    "city": "Monterrey",
    "source": "FIFA / MLS Soccer"
  }
]

来按球队查下:

python3 worldcup_helper.py --team Mexico

再按日期查:

python3 worldcup_helper.py --date 2026-06-18

从上图可以看到,脚本现在查的是北京时间日期。虽然这两场比赛的举办地日期都是 2026-06-18,但换算成北京时间后已经是 2026-06-19。所以输入 2026-06-18 查不到比赛,输入 2026-06-19 才能查到这两场。

这也是我们把 --date 设计成本地观赛日期的原因:我们关心的是“我这一天能看哪些比赛”,而不是比赛举办地的日期。

此外,如果不加参数,脚本会默认输出 matches.json 里所有比赛:

python3 worldcup_helper.py

小结

到这里,一个最小版的世界杯赛程助手已经能跑了。

它做的事情很朴素:读取 JSON、查比赛、转时区、输出结果。但这个朴素的结构很重要,因为它把几个容易出错的地方拆清楚了。赛程数据不能只写一句“6 月 18 日晚上比赛”,而要拆成:

当地日期
当地时间
比赛所在时区
对阵球队
比赛城市
比赛场馆

按日期查询时,我们要先想清楚:用户输入的日期,指的是比赛举办地日期,还是自己所在时区看到的日期。对使用者来说,更自然的查询方式肯定是按北京时间查询,因为大家真正关心的是“我这一天能看哪些比赛”。

世界杯赛程只是一个小例子。类似的问题在很多场景里都会出现,比如跨国会议、线上活动、直播排期、航班时间、促销活动上线时间。只要涉及不同时区,最好都不要把时间当成一个普通字符串随手存下来。

这篇小工具可以总结成一句话:先把数据结构化,再用程序处理确定性的查询和计算。

这样做出来的工具,功能不一定复杂,但结果会更可靠。世界杯只是一个入口,真正值得练的是这种处理数据和时间的基本思路。

相关文章
|
27天前
|
开发框架 测试技术 定位技术
Codex 实践系列 Vol.02:让 Codex 读懂开源项目 Typer
这次用 Codex 读 Typer,最重要的一点是:面对一个新项目,第一步先别急着让它写代码。比较稳妥的做法,是先让 Codex 读目录、找入口、解释核心文件,再沿着一个具体功能追下去,最后通过测试理解项目如何验证行为。
203 3
Codex 实践系列 Vol.02:让 Codex 读懂开源项目 Typer
|
26天前
|
弹性计算 负载均衡 安全
阿里云负载均衡(SLB)从入门到精通:完整配置流程与最佳实践
本文详细讲解阿里云负载均衡(SLB)的完整配置流程,涵盖实例创建、服务器组配置、监听设置、健康检查、安全策略及优化实践,同时包含常见问题解答,帮助用户快速掌握SLB部署与运维核心技能。
|
23天前
|
机器学习/深度学习 自然语言处理 安全
从零构建车载语音对话系统:NLU → DST → Policy → NLG → TTS 全链路工程实践
本文详解车载语音助手全链路工程实践,涵盖NLU(意图识别+槽位抽取)、DST(多轮状态追踪)、Policy(安全驱动决策)、NLG(模板化自然语言生成)与TTS(双引擎语音合成)五大模块,基于Pipeline架构实现高可解释、可调试、强安全的工业级Demo,代码开源、开箱即用。(239字)
|
NoSQL Java 关系型数据库
【AgentScope Java新手村系列】(5)记忆与会话管理
记忆与会话管理 — AgentState 管理上下文窗口,AgentStateStore 持久化,RuntimeContext.sessionId 隔离多用户会话。
277 0
|
26天前
|
存储 人工智能 算法
Claude Code自我进化系统解析:AI编程助手持久化记忆与行为学习实现方案
在日常使用Claude Code开展编程工作时,多数用户都会遇到一个普遍痛点:每开启一次全新会话,AI都会清空此前的对话内容、项目认知与个人编码习惯。此前沟通的项目架构、反复确认的代码规范、调试总结的经验教训都需要重新讲解,不仅耗费大量时间,还会降低整体开发效率。针对这一问题,业内技术团队基于Claude Code原生能力,搭建了一套完整的持久化记忆与自我进化系统,让这款AI编程助手能够跨会话留存信息、自主学习用户行为规律,逐步适配个人与团队的开发模式。本文将完整拆解这套系统的整体架构、核心模块、技术实现、运行流程以及落地效果,同时讲解设计思路与优化细节,为AI编程工具的深度定制提供参考。
223 4
|
26天前
|
缓存 人工智能 自然语言处理
阿里云百炼通义千问Qwen3.6-Flash完整实操指南:轻量化旗舰功能特性、落地优势与分层优惠订阅方案详解
当前AI应用落地场景分化愈发明显,除复杂智能体、百万字长文档、全栈大型工程开发等高门槛业务外,大量企业存在高频轻量问答、实时客服对话、短文本批量生成、简单数据提取、前端实时交互等标准化轻量化需求。这类场景单日调用频次可达数万乃至数十万次,对接口响应延迟、单轮调用成本、并发承载能力有极高要求,若选用高规格旗舰模型会造成算力预算严重浪费,而普通基础轻量化模型又存在逻辑推理弱、工具调用不稳定、短文本输出质量差等短板。
396 4
|
26天前
|
人工智能 缓存 监控
阿里云百炼Token Plan全维度详解:核心功能、团队使用优势与AI生产力模型订阅实操指南
随着AI智能体、长文档解析、全栈代码开发、多模态图文分析等业务在企业内部常态化落地,绝大多数团队在大模型调用过程中暴露出一系列成本与管理痛点:按量付费模式账单波动剧烈,业务高峰期调用量激增导致月度预算严重超支;多员工共用模型资源时无法实现额度隔离,单人超额消耗会挤占整个团队算力;不同型号大模型单价差异大,切换模型后计费规则不统一,财务核算流程繁琐;算力高峰时段按量调用容易出现排队延迟、接口限流,影响业务系统稳定运行;团队缺乏统一的用量监控、权限分级、预算预警能力,AI资源使用处于无管控状态。
224 1
|
26天前
|
人工智能 缓存 运维
阿里云百炼通义千问Qwen3.7-Plus完整指南:全维度功能特性、落地优势与优惠订阅方案实操手册
AI应用规模化落地进程中,绝大多数企业与开发者面临性能与成本难以平衡的核心难题:轻量化模型推理、图文解析、长文档处理能力不足,无法支撑中等复杂度智能体任务;旗舰级模型长期高频调用成本偏高,中小团队难以持续投入算力预算。依托自研通义千问技术体系打造的Qwen3.7-Plus,是阿里云百炼平台推出的中端全能型多模态大模型,精准填补轻量化模型与旗舰模型之间的市场空白,在保留百万级上下文、原生图文多模态、全链路工具调用、通用代码生成全套核心能力的基础上,大幅下调调用单价,适配个人开发者、小微创业团队、中小企业全层级使用需求。
599 1
|
26天前
|
缓存 人工智能 运维
阿里云百炼Qwen3.7-Max全解:旗舰模型核心能力、技术优势与优惠订阅方案实操指南
AI智能体技术进入规模化落地阶段后,市场对大模型的长文本承载、多步骤自主推理、工具链式调用、全栈代码开发能力提出前所未有的高标准。传统轻量化对话模型仅能满足基础问答,无法支撑企业级长周期自动化任务、复杂软件工程、海量文档深度分析等高价值场景。阿里云依托自研通义千问技术体系,在百炼大模型服务平台正式推出Qwen3.7-Max旗舰大模型,作为当前千问3.7系列综合性能天花板,全面对标国际头部闭源旗舰模型,专为智能体全链路工作流深度优化,兼顾推理精度、并发稳定性、多模态理解与成本可控性,同时配套分层订阅优惠计划,覆盖个人开发者、小微团队、中大型集团企业全维度使用需求。本文将完整拆解Qwen3.7-M
382 1