NTP库详解

发布于:2025-06-03 ⋅ 阅读:(16) ⋅ 点赞:(0)

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, timezone

def 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_str
    except ValueError as ve:
        print(f"输入格式错误: {ve}")
        return None, None
    except 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);

  // 连接 WiFi
  WiFi.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:SS
  String 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);

  // 连接WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  // 启动NTPClient
  timeClient.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);

  // 连接WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  // 启动NTPClient
  timeClient.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); // 每秒更新一次
}

网站公告

今日签到

点亮在社区的每一天
去签到