当前位置: 首页 > news >正文

NTP库详解

NTPClient

NTPClient 库为 Arduino 提供了连接 NTP 服务器并获取准确时间的功能。

项目地址:https://github.com/arduino-libraries/NTPClient

UTC时间戳计算工具

https://www.epochconverter.com/

核心函数

构造函数

NTPClient(UDP& udp)

  • 功能:创建一个 NTPClient 对象,使用默认的 NTP 服务器 pool.ntp.org,无时间偏移,更新间隔为 60 秒。
  • 示例
#include <WiFiUdp.h>
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);

NTPClient(UDP& udp, long timeOffset)

  • 功能:创建一个 NTPClient 对象,指定时间偏移量(以秒为单位)。
  • 示例
#include <WiFiUdp.h>
WiFiUDP ntpUDP;
long offset = 3600; // 偏移1小时
//long offset = 8 * 3600; // 北京时间,东八区,偏移8小时
NTPClient timeClient(ntpUDP, offset);

NTPClient(UDP& udp, const char* poolServerName)

  • 功能:创建一个 NTPClient 对象,指定 NTP 服务器名称。
  • 示例
#include <WiFiUdp.h>
WiFiUDP ntpUDP;
const char* serverName = "europe.pool.ntp.org";
NTPClient timeClient(ntpUDP, serverName);

NTPClient(UDP& udp, IPAddress poolServerIP)

  • 功能:创建一个 NTPClient 对象,指定 NTP 服务器的 IP 地址。
  • 示例
#include <WiFiUdp.h>
WiFiUDP ntpUDP;
IPAddress serverIP(192, 168, 1, 100);
NTPClient timeClient(ntpUDP, serverIP);

NTPClient(UDP& udp, const char* poolServerName, long timeOffset)

  • 功能:创建一个 NTPClient 对象,指定 NTP 服务器名称和时间偏移量。
  • 示例
#include <WiFiUdp.h>
WiFiUDP ntpUDP;
const char* serverName = "europe.pool.ntp.org";
long offset = 3600;
NTPClient timeClient(ntpUDP, serverName, offset);

NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset)

  • 功能:创建一个 NTPClient 对象,指定 NTP 服务器的 IP 地址和时间偏移量。
  • 示例
#include <WiFiUdp.h>
WiFiUDP ntpUDP;
IPAddress serverIP(192, 168, 1, 100);
long offset = 3600;
NTPClient timeClient(ntpUDP, serverIP, offset);

NTPClient(UDP& udp, const char* poolServerName, long timeOffset, unsigned long updateInterval)

  • 功能:创建一个 NTPClient 对象,指定 NTP 服务器名称、时间偏移量和更新间隔(以毫秒为单位)。
  • 示例
#include <WiFiUdp.h>
WiFiUDP ntpUDP;
const char* serverName = "europe.pool.ntp.org";
long offset = 3600;
unsigned long interval = 120000; // 2分钟更新一次
NTPClient timeClient(ntpUDP, serverName, offset, interval);

NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset, unsigned long updateInterval)

  • 功能:创建一个 NTPClient 对象,指定 NTP 服务器的 IP 地址、时间偏移量和更新间隔。
  • 示例
#include <WiFiUdp.h>
WiFiUDP ntpUDP;
IPAddress serverIP(192, 168, 1, 100);
long offset = 3600;
unsigned long interval = 120000;
NTPClient timeClient(ntpUDP, serverIP, offset, interval);

成员函数

void begin()

  • 功能:启动底层 UDP 客户端,使用默认的本地端口 NTP_DEFAULT_LOCAL_PORT(1337)。
  • 示例
timeClient.begin();

void begin(unsigned int port)

  • 功能:启动底层 UDP 客户端,使用指定的本地端口。
  • 示例
unsigned int port = 1234;
timeClient.begin(port);

bool update()

  • 功能:根据更新间隔检查是否需要从 NTP 服务器更新时间。如果需要更新,则进行更新并返回 true;否则返回 false
  • 示例
if (timeClient.update()) {Serial.println("Time updated successfully");
} else {Serial.println("Time not updated");
}

bool forceUpdate()

  • 功能:强制从 NTP 服务器更新时间。更新成功返回 true,失败返回 false
  • 示例
if (timeClient.forceUpdate()) {Serial.println("Forced time update successful");
} else {Serial.println("Forced time update failed");
}

bool isTimeSet() const

  • 功能:检查 NTPClient 是否成功接收 NTP 数据包并设置了时间。如果时间已设置,返回 true;否则返回 false
  • 示例
if (timeClient.isTimeSet()) {Serial.println("Time is set");
} else {Serial.println("Time is not set");
}

int getDay() const

  • 功能:获取当前是星期几(0 表示星期日)。
  • 示例
int day = timeClient.getDay();
Serial.print("Day of the week: ");
Serial.println(day);

int getHours() const

  • 功能:获取当前小时数(0 - 23)。
  • 示例
int hours = timeClient.getHours();
Serial.print("Hours: ");
Serial.println(hours);

int getMinutes() const

  • 功能:获取当前分钟数(0 - 59)。
  • 示例
int minutes = timeClient.getMinutes();
Serial.print("Minutes: ");
Serial.println(minutes);

int getSeconds() const

  • 功能:获取当前秒数(0 - 59)。
  • 示例
int seconds = timeClient.getSeconds();
Serial.print("Seconds: ");
Serial.println(seconds);

String getFormattedTime() const

  • 功能:返回格式化的时间字符串,格式为 hh:mm:ss。有设置偏移的话,这个是偏移后的时间。
  • 示例
String formattedTime = timeClient.getFormattedTime();
Serial.println(formattedTime);

unsigned long getEpochTime() const

  • 功能:返回自 1970 年 1 月 1 日 00:00:00 UTC 以来的秒数(Unix 时间戳)。如果设置了时间偏移量,该偏移量将被添加到时间戳中。

时间戳(timestamp)是一个绝对的时间表示,通常定义为从1970 年 1 月 1 日 00:00:00
UTC
开始经过的秒数。时间戳与时区无关,无论你在哪个时区,同一时刻的时间戳都是相同的。

北京时间的时间戳与 UTC 时间戳在同一时刻应该是完全相同的,不需要加上时区偏移。

注意:NTP库函数定义:getEpochTime()返回值 = UTC纪元时间戳 + 时间偏移量

  • 示例
unsigned long epochTime = timeClient.getEpochTime();
Serial.print("Epoch time: ");
Serial.println(epochTime);
UTC纪元时间戳

1.在线工具

https://www.epochconverter.com/

2.python计算

from datetime import datetime, timedelta, timezonedef beijing_time_to_utc_timestamp(date_str, time_str="00:00:00"):"""将北京时间(格式:YYYY.M.D)转换为UTC纪元时间戳参数:- date_str: 日期字符串,例如 "2025.3.5"- time_str: 时间字符串,例如 "12:30:45"(默认00:00:00)返回:- utc_timestamp: UTC时间戳(秒级)- utc_time_str: UTC时间字符串(格式:YYYY-MM-DD HH:MM:SS)"""try:# 解析日期和时间year, month, day = map(int, date_str.split('.'))hour, minute, second = map(int, time_str.split(':'))# 创建北京时间的时区对象(UTC+8)beijing_tz = timezone(timedelta(hours=8))# 创建带时区的北京时间对象beijing_time = datetime(year, month, day, hour, minute, second, tzinfo=beijing_tz)# 转换为UTC时间utc_time = beijing_time.astimezone(timezone.utc)# 计算UTC时间戳utc_timestamp = int(utc_time.timestamp())# 格式化为字符串utc_time_str = utc_time.strftime("%Y-%m-%d %H:%M:%S")return utc_timestamp, utc_time_strexcept ValueError as ve:print(f"输入格式错误: {ve}")return None, Noneexcept Exception as e:print(f"发生未知错误: {e}")return None, None# 示例使用
if __name__ == "__main__":# 用户输入案例input_date = input("STEP 1/2:请输入日期(格式:年.月.日,例如:2025.3.5):")input_time = input("STEP 2/2:请输入时间(格式:时:分:秒,例如:12:30:45,默认为00:00:00):")# 处理默认时间if not input_time.strip():input_time = "00:00:00"# 计算UTC时间戳和UTC时间timestamp, utc_str = beijing_time_to_utc_timestamp(input_date, input_time)# 打印结果if timestamp is not None:print(f"输入北京时间:{input_date} {input_time}")print(f"对应的UTC时间:{utc_str}")print(f"UTC纪元时间戳(注意:NTP库getEpochTime() = UTC纪元时间戳 + 时间偏移量):{timestamp}")    

void end()

  • 功能:停止底层 UDP 客户端。
  • 示例
timeClient.end();

void setTimeOffset(int timeOffset)

  • 功能:设置时间偏移量(以秒为单位),可动态更改时区。
  • 示例
int offset = 7200; // 偏移2小时
timeClient.setTimeOffset(offset);

void setUpdateInterval(unsigned long updateInterval)

  • 功能:设置时间更新间隔(以毫秒为单位)。
  • 示例
unsigned long interval = 180000; // 3分钟更新一次
timeClient.setUpdateInterval(interval);

void setPoolServerName(const char* poolServerName)

  • 功能:设置 NTP 服务器名称。
  • 示例
const char* serverName = "asia.pool.ntp.org";
timeClient.setPoolServerName(serverName);

void setRandomPort(unsigned int minValue, unsigned int maxValue)

  • 功能:设置一个随机的本地端口,端口范围在 minValuemaxValue 之间。
  • 示例
unsigned int minPort = 49152;
unsigned int maxPort = 65535;
timeClient.setRandomPort(minPort, maxPort);

示例

格式化时间1

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>// WiFi网络信息
const char *ssid = "<SSID>";
const char *password = "<PASSWORD>";// NTP服务器地址
const char* ntpServerName = "ntp.aliyun.com";
// 北京时间所在时区为UTC+8
const long gmtOffset_sec = 8 * 3600;
// 设置NTP更新最小时间间隔,参数单位为毫秒
const int daylightOffset_sec = 60000;// 创建WiFiUDP对象
WiFiUDP ntpUDP;
// 创建NTPClient对象
NTPClient timeClient(ntpUDP, ntpServerName, gmtOffset_sec, daylightOffset_sec);void setup() {Serial.begin(115200);// 连接 WiFiWiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.println("Connecting to WiFi...");}Serial.println("Connected to WiFi");// 初始化 NTP 客户端timeClient.begin();
}void loop() {// 更新 NTP 时间timeClient.update();// 获取格式化后的时间字符串,HH:MM:SSString formattedTime = timeClient.getFormattedTime();// 打印原始格式化时间Serial.print("Formatted Time: ");Serial.println(formattedTime);// 提取小时、分钟和秒int hour, minute, second;  // 从格式化时间字符串中提取小时hour = formattedTime.substring(0, 2).toInt();  // 从格式化时间字符串中提取分钟minute = formattedTime.substring(3, 5).toInt();  // 从格式化时间字符串中提取秒second = formattedTime.substring(6, 8).toInt();// 打印提取的时间位Serial.print("Hour: ");Serial.print(hour);Serial.print(", Minute: ");Serial.print(minute);Serial.print(", Second: ");Serial.println(second);// timeClient.getEpochTime()返回自 1970-01-01 00:00:00 UTC 以来的秒数(即Unix时间戳)unsigned long epochTime = timeClient.getEpochTime();  Serial.print("Epoch Time: ");Serial.println(epochTime);delay(1000);
}

格式化时间2

#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>// WiFi网络信息
const char *ssid = "<SSID>";
const char *password = "<PASSWORD>";// 创建WiFi UDP客户端
WiFiUDP ntpUDP;// 创建NTPClient对象,使用默认的NTP服务器,东八区(偏移28800秒),更新间隔为60秒
NTPClient timeClient(ntpUDP, "pool.ntp.org", 28800, 60000);// 定义中文星期数组
const char* weekDays[] = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};// 补零函数
String zeroPad(int num) {return (num < 10) ? "0" + String(num) : String(num);
}void setup() {// 初始化串口通信Serial.begin(115200);// 连接WiFiWiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(500);Serial.print(".");}Serial.println("");Serial.println("WiFi connected");// 启动NTPClienttimeClient.begin();
}void loop() {// 更新时间timeClient.update();// 获取星期、小时、分钟和秒int day = timeClient.getDay();int hours = timeClient.getHours();int minutes = timeClient.getMinutes();int seconds = timeClient.getSeconds();// 格式化输出String formattedTime = weekDays[day] + String(" ") + zeroPad(hours) + ":" + zeroPad(minutes) + ":" + zeroPad(seconds);Serial.println(formattedTime);delay(1000); // 每秒更新一次
}

距离目标时间还有多久

#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>// WiFi网络信息
const char *ssid = "<SSID>";
const char *password = "<PASSWORD>";// 创建WiFi UDP客户端
WiFiUDP ntpUDP;// 创建NTPClient对象,使用默认的NTP服务器,东八区(偏移28800秒),更新间隔为60秒
NTPClient timeClient(ntpUDP, "pool.ntp.org", 28800, 60000);// 2025年6月14日星期六凌晨12点00分 GMT+08:00
// 用https://www.epochconverter.com/在线工具计算时间戳
// 工具计算出的时间戳为UTC纪元时间戳,getEpochTime() = UTC纪元时间戳 + 时间偏移量
// 所以计算剩余时间,需要加上时区偏移
const unsigned long targetTime = 1749830400;void setup() {// 初始化串口通信Serial.begin(115200);// 连接WiFiWiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(500);Serial.print(".");}Serial.println("");Serial.println("WiFi connected");// 启动NTPClienttimeClient.begin();}void loop() {// 更新时间timeClient.update();Serial.println(timeClient.getFormattedTime());Serial.println(timeClient.getEpochTime());// 获取当前时间戳unsigned long currentTime = timeClient.getEpochTime();// 计算剩余时间,计算时间差需要加上时区偏移long remainingTime = targetTime - currentTime + 8 * 3600;if (remainingTime > 0) {// 显示剩余时间Serial.print("Remaining time: ");unsigned long days = remainingTime / (24 * 3600);String daysStr = days < 10 ? "0" + String(days) : String(days);Serial.print(daysStr);Serial.print("d:");remainingTime %= (24 * 3600);unsigned long hours = remainingTime / 3600;String hoursStr = hours < 10 ? "0" + String(hours) : String(hours);Serial.print(hoursStr);Serial.print("h:");remainingTime %= 3600;unsigned long minutes = remainingTime / 60;String minuteStr = minutes < 10 ? "0" + String(minutes) : String(minutes);Serial.print(minuteStr);Serial.print("m:");unsigned long seconds = remainingTime % 60;String secondStr = seconds < 10 ? "0" + String(seconds) : String(seconds);Serial.print(secondStr);Serial.println("s");} else {Serial.println("Countdown finished!");}delay(1000); // 每秒更新一次
}

相关文章:

  • JavaScript性能优化:实战技巧提升10倍速度
  • 【笔记】如何卸载 MSYS2 中不同工具链的 numpy 包
  • TDengine 的 AI 应用实战——电力需求预测
  • vue-12 (路由守卫:全局、每个路由和组件内)
  • 黑马Java面试笔记之 微服务篇(SpringCloud)
  • 第12次12: 修改和删除收货地址
  • 前端面试宝典---前端水印
  • DeepSeek模型安全部署与对抗防御全攻略
  • C语言:内存函数
  • C++ 内存泄漏检测器设计
  • 第17讲、odoo18可视化操作代码生成模块
  • 鸿蒙进阶——Mindspore Lite AI框架源码解读之模型加载详解(二)
  • Linux之进程间通信
  • 用“照片放大/缩小”来通俗理解多尺度
  • Altium Disigner(16.1)学习-元器件封装
  • 【看到哪里写到哪里】C的指针-3(函数指针)
  • 【Java Web】6.登入认证
  • Missashe考研日记—Day51-Day57
  • 网络安全的学习路线是怎么样的?
  • 已有的前端项目打包到tauri运行(windows)
  • 企业做网站的方案/活动推广朋友圈文案
  • 连云港网站建设电话/推广关键词如何优化
  • 求职网站网页设计/上海网络推广公司排名
  • wordpress php sqlite/整站seo免费咨询
  • 专做温州鞋批发的网站/网站访问量
  • linux网站做301重定向/百度客户端官网