如何在PHP和MySQL中根据国家ISO码筛选当地处于下午的用户
问题描述
我用CRON任务运行PHP脚本,需要根据收件人国家ISO码对应的当地时间在下午发送邮件。我没存储UTC时间,只能通过用户的国家ISO码确定时区。服务器配置为法国时区(UTC+0200),请问怎么筛选当前当地时间处于下午的用户?
MySQL用户表结构及数据:
+------------+-----------+---------------------+---------------------+ | company | Country | Email | Date | +------------+-----------+---------------------+---------------------+ | ABC | US | john.doe@domain.com | 2018-08-19 12:53:58 | | DEF | FR | doe.john@domain.com | 2021-10-04 08:12:27 | | GHJ | CN | john.d@domain.com | 2022-03-15 17:32:19 | +------------+-----------+---------------------+---------------------+
解决方案
核心要做的就是把服务器时间转换成用户所在时区的当地时间,再判断是否处于下午区间(比如12:00-18:00,可按需调整)。首先得先把国家ISO码对应到具体的时区标识符——毕竟部分国家有多个时区,这里默认用该国的主要时区。
1. 准备时区映射关系
可以用PHP数组存,也可以在MySQL里建辅助表:
PHP数组示例
$countryTimezones = [ 'US' => 'America/New_York', // 美国东部时区,可根据用户实际分布调整 'FR' => 'Europe/Paris', 'CN' => 'Asia/Shanghai' ];
MySQL辅助表(可选)
CREATE TABLE country_timezones ( country_code CHAR(2) PRIMARY KEY, timezone VARCHAR(50) NOT NULL ); INSERT INTO country_timezones VALUES ('US', 'America/New_York'), ('FR', 'Europe/Paris'), ('CN', 'Asia/Shanghai');
2. 方式一:MySQL直接筛选
利用MySQL的CONVERT_TZ函数,先把服务器当前时间(法国时区)转成UTC,再转成用户时区的当地时间,最后提取小时数判断是否在下午区间。
注意:要确保MySQL的时区表已加载,可通过SELECT * FROM mysql.time_zone_name;检查,为空的话需要导入时区数据。
查询语句示例(下午定义为12:00-18:00):
SELECT u.* FROM users u JOIN country_timezones ct ON u.Country = ct.country_code WHERE HOUR(CONVERT_TZ(NOW(), 'Europe/Paris', ct.timezone)) BETWEEN 12 AND 17;
NOW()获取服务器当前的法国时区时间CONVERT_TZ完成两次转换:服务器时间→UTC时间→用户时区当地时间HOUR()提取小时数,判断是否落在12到17之间(对应12:00-18:00)
3. 方式二:PHP中处理筛选
先从数据库取出所有用户,再在PHP里做时区转换和判断:
// 先把脚本时区设为服务器的法国时区 date_default_timezone_set('Europe/Paris'); // 时区映射数组 $countryTimezones = [ 'US' => 'America/New_York', 'FR' => 'Europe/Paris', 'CN' => 'Asia/Shanghai' ]; // 连接数据库并获取所有用户 $pdo = new PDO('mysql:host=localhost;dbname=你的数据库名;charset=utf8', '用户名', '密码'); $stmt = $pdo->query('SELECT * FROM users'); $users = $stmt->fetchAll(PDO::FETCH_ASSOC); // 筛选当地时间在下午的用户 $afternoonUsers = []; // 先拿UTC时间,避免服务器时区变动影响 $currentUtc = new DateTime('now', new DateTimeZone('UTC')); foreach ($users as $user) { $countryCode = $user['Country']; if (!isset($countryTimezones[$countryCode])) { continue; // 跳过没配置时区的用户 } $userTimezone = new DateTimeZone($countryTimezones[$countryCode]); $userLocalTime = $currentUtc->setTimezone($userTimezone); $hour = (int)$userLocalTime->format('H'); // 判断是否为下午(这里是12:00-18:00) if ($hour >= 12 && $hour < 18) { $afternoonUsers[] = $user; } } // 接下来对$afternoonUsers执行发送邮件的操作
注意事项
- 时区映射要准确:比如美国有多个时区,如果用户分布在不同时区,可能需要更细的地区数据,而不只是国家码
- 下午的时间区间可根据需求调整,比如改成13:00-17:00
- CRON任务建议每小时执行一次,或者每15分钟一次,避免错过时区边界的用户
内容的提问来源于stack exchange,提问作者Mary
相关产品推荐
相关产品推荐

