外观
时间
约 22289 字大约 74 分钟
简介
在Mine Script®中,处理日期和时间值时需注意以下关键方面:
- UNIX时间戳:Mine中时间值的原生格式,表示自UTC时间1970年1月1日午夜以来经过的绝对毫秒数。多个内置函数直接返回UNIX时间戳,用户可将其格式化为可读的日期和时间。更多信息请参阅下方的UNIX时间戳部分。
- 交易所时区:标的品种交易所所在的时区。所有基于日历的变量值均以交易所时区表示,所有带有
timezone参数的内置函数重载默认使用此时区。 - 图表时区:图表及Mine日志消息前缀用于显示时间值的时区。用户可通过图表设置中“品种”标签页的“时区”输入项设置图表时区。此设置仅改变图表上日期和时间的显示方式以及日志消息前缀的时间,不会影响Mine脚本的行为,因为脚本无法访问图表的时区信息。
timezone参数:时间相关函数的“字符串”参数,用于指定计算中使用的时区。对于基于日历的函数(如dayofweek()),该参数决定返回值的时区;对于返回UNIX时间戳的函数(如time()),指定的时区用于定义其他相关参数(例如session)的时区。更多信息请参阅时区字符串部分。
UNIX时间戳
UNIX时间是一种标准化的日期和时间表示方法,用于计算自UTC时间1970年1月1日00:00:00(UNIX纪元)以来经过的非闰秒数,通常以秒或更小的时间单位表示。在Mine Script中,UNIX时间值是一个“int”类型的时间戳,表示从UNIX纪元到特定时间点的毫秒数。
由于UNIX时间戳表示的是从一个固定历史点(纪元)开始经过的恒定时间单位数量,因此其值与时区无关。无论用户位于何处,Mine中的UNIX时间戳始终对应同一个精确到毫秒的特定时间点。
例如,UNIX时间戳1723472500000始终表示UNIX纪元之后的1,723,472,500,000毫秒(即1,723,472,500秒)。该时间戳的含义不会因任何时区而改变。
若要将“int”类型的UNIX时间戳格式化为以特定时区表示的可读日期/时间“字符串”,可使用str.format_time()函数。该函数不会修改UNIX时间戳,而只是以所需的人类可读格式表示时间戳。
例如,该函数可以根据其format和timezone参数,将UNIX时间戳1723472500000以多种方式表示为“字符串”,而不会改变其所指的绝对时间点。以下简单脚本计算了该时间戳的三种有效表示形式,并在Mine日志面板中显示:

Mine Script®
已复制
请注意:
- 日志消息中由方括号括起的值是自动添加的前缀,表示调用log.info()时的历史时间(以ISO 8601格式表示),并使用图表时区显示。
关于如何用格式化字符串表示UNIX时间戳的更多信息,请参阅格式化日期和时间部分。
时区
时区是指具有统一本地时间的特定地理区域。同一时区内的具体时间在整个区域内保持一致。时区边界通常与地理经度相关,但实际上往往遵循行政边界划分,而非严格按经度线划分。
时区的本地时间取决于其与协调世界时(UTC)的固定偏移量,范围可从UTC-12:00(比UTC慢12小时)至UTC+14:00(比UTC快14小时)。部分区域始终维持固定UTC偏移量,另一些区域则会因夏令时(DST)等因素随时间调整偏移量。
在数据源和TradingVue图表中主要涉及两种时区:交易所时区和图表时区。
交易所时区代表当前交易品种所属交易所的时区,Mine脚本可通过syminfo.timezone变量获取该时区。所有基于日历的变量(如month、dayofweek和hour)始终以交易所时区表示数值,且所有带timezone参数的时间函数默认均采用此时区。
图表时区属于视觉偏好设置,决定图表界面和Mine日志时间前缀的显示方式。用户可通过图表设置中“品种”标签页的“时区”选项,或直接点击图表下方显示的时间进行设置。该设定不会影响Mine脚本的时间计算,因为脚本无法获取图表时区信息。虽然脚本无法读取图表时区,但程序员可通过创建输入参数供用户调整以匹配所需时区。
例如,下方脚本使用str.format_time()将最近一根历史K线的开盘时间与收盘时间UNIX时间戳,分别转换为四种时区(函数默认时区、交易所时区、UTC-0和用户指定时区)的日期时间字符串,并在图表右下角的表格中并列显示以供对比:

Mine Script®
已复制
请注意:
- 图表上的标签标示了所显示时间字符串对应的K线。
- 表格中“默认”和“交易所”两行显示结果相同,因为syminfo.timezone是str.format_time()函数的默认时区参数。
- 本示例图表中的交易所时区显示为
"America/New_York",这是纳斯达克交易所时区的IANA标识符。该时区对应UTC-4或UTC-5,具体取决于一年中的不同时段。更多关于时区字符串的信息,请参阅下一节。
时区字符串
所有带有timezone参数的内置函数都接受一个“string”参数,用于指定计算中使用的时区。这些函数可以接受以下两种格式的时区字符串:
- UTC(或GMT)偏移表示法,例如:
"UTC-5","UTC+05:30","GMT+0100" - IANA数据库表示法,例如:
"America/New_York","Asia/Calcutta","Europe/Paris"
IANA时区数据库参考页面列出了所有可能的时区标识符及其对应的UTC偏移量。这些标识符都可以作为timezone参数的有效值。
需要注意的是,使用不同格式的时区字符串可能表示相同的UTC偏移量。例如,以下字符串都表示比UTC快3小时的时区:
"UTC+3""GMT+03:00""Asia/Kuwait""Europe/Moscow""Africa/Nairobi"
对于str.format_time()函数以及基于UNIX时间戳计算日历值的函数(如month()、dayofweek()和hour()),传递给timezone参数的“string”会改变返回值的计算方式,使其结果反映指定时区的时间。更多信息请参阅格式化日期和时间以及基于日历的函数部分。
下面的示例展示了时区字符串如何影响基于日历函数的返回值。该脚本使用三个hour()函数调用,分别计算每根K线在交易所时区、UTC-0和用户指定的UTC偏移量下的开盘小时数(“int”类型)。它将所有三个计算结果绘制在单独的面板中以供比较:

Mine Script®
已复制
请注意:
exchangeHour值比utcHour慢4或5小时,因为纳斯达克交易所位于"America/New_York"时区。该时区的UTC偏移量会因夏令时(DST)在一年中发生变化。而脚本的默认customOffsetHour始终比utcHour快4小时,因为其指定时区为UTC+4。- 未指定
timezone参数的hour()函数调用返回的值与hour变量相同,因为两者都表示交易所时区(syminfo.timezone)的K线开盘小时数。
对于直接返回UNIX时间戳的函数(如time()和timestamp()),timezone参数仅定义函数中基于日历的参数(包括session、year、month、day、hour、minute和second)所属时区,而不会影响返回值本身的时区,因为UNIX时间戳本身与时区无关。更多信息请参阅测试交易时段和timestamp()部分。
以下脚本调用timestamp()函数计算特定日期时间的UNIX时间戳,并在对应K线位置绘制标签。用户选择的timezone参数(timezoneInput)决定了函数中基于日历参数的时区。因此,相同的本地时间在不同时区下会计算出不同的时间戳值,因为它们距离UNIX纪元的时间长度不同:

Mine Script®
已复制
请注意:
"Etc/UTC"是 UTC+0 时区的 IANA 标识符。- label.new() 调用使用 xloc.bar_time 作为其
xloc参数,这是将绘图锚定到绝对时间值所必需的。没有此参数,函数会将unixTimestamp视为相对柱索引,导致位置不正确。 - 标签的
y值是开盘时间与unixTimestamp相交柱的收盘价。如果时间戳代表未来时间,则标签使用最后一根历史柱的价格。
虽然时区字符串可以使用 UTC 或 IANA 表示法,但在大多数情况下,我们建议在 timezone 参数中使用 IANA 表示法,特别是当脚本的时间计算必须与特定国家或地区的观测时间偏移对齐时。当时间函数调用使用 IANA 时区标识符作为其 timezone 参数时,其计算会自动调整以适应指定地区观测时间的历史和未来变化,例如夏令时 (DST) 和时区边界的更新,而不是使用固定的 UTC 偏移量。
以下脚本演示了 UTC 和 IANA 时区字符串如何以不同方式影响时间计算。它使用两个 hour() 函数调用,分别使用 "UTC-4" 和 "America/New_York" 作为 timezone 参数,从当前柱的开盘时间戳计算小时数。脚本绘制两个调用的结果进行比较,并在返回值不匹配时为主窗格背景着色。虽然这两个 hour() 调用看起来相似,因为 UTC-4 是纽约的观测 UTC 偏移量,但它们并不总是返回相同的结果,如下所示:

Mine Script®
已复制
上图中两条曲线会周期性偏离,这是因为纽约实行夏令时制度,导致其UTC偏移量在一年中特定时间点会发生变化。在夏令时期间,纽约本地时间采用UTC-4标准;而在非夏令时期间则采用UTC-5标准。由于脚本第一个hour()调用使用"UTC-4"作为时区参数,它仅在夏令时期间能返回纽约的正确小时数。而使用"America/New_York"时区字符串的调用,则会自动调整UTC偏移量,从而全年任何时段都能返回纽约的正确小时数。
时间变量
Mine Script提供多个内置变量,使脚本能够获取不同形式的时间信息:
- time和time_close变量存储UNIX时间戳,分别表示当前K线的开盘时间和收盘时间
- time_tradingday变量存储UNIX时间戳,表示交易时段中最后一个UTC日历日的开始时间
- timenow变量存储UNIX时间戳,表示脚本执行时的当前时间
- year、month、weekofyear、dayofmonth、dayofweek、hour、minute和second变量基于当前K线开盘时间,返回交易所时区的日历值
- last_bar_time变量存储UNIX时间戳,表示最后一根可用K线的开盘时间
- chart.left_visible_bar_time和chart.right_visible_bar_time变量存储UNIX时间戳,分别表示图表最左侧和最右侧可见K线的开盘时间
- syminfo.timezone变量存储“string”值,以IANA数据库表示法表示当前交易品种所属交易所的时区。所有带
timezone参数的时间相关函数都默认使用此变量作为参数
time和time_close变量
time变量存储当前K线开盘时间的UNIX时间戳,time_close变量存储K线收盘时间的UNIX时间戳。
这些时间戳是唯一的、与时区无关的“int”值,程序员可以用它们来将绘图对象锚定到特定K线时间,计算和检查K线时间差,使用str.format_time()函数构建可读的日期/时间字符串等。
以下脚本以不同方式显示K线开盘和收盘时间。在每个K线上,它将time和time_close时间戳格式化为包含交易所时区小时、分钟和秒的字符串,并在开盘价和收盘价位置绘制标签显示这些格式化字符串。此外,脚本还在图表右下角的表格中显示最后一根K线未经格式化的UNIX时间戳字符串:

Mine Script®
已复制
请注意:
- 此脚本的label.new()调用包含xloc.bar_time作为
xloc参数和time作为x参数,以将绘图锚定到K线开盘时间。 - 格式化字符串以交易所时区表示时间,因为我们没有在str.format_time()调用中指定
timezone参数。我们图表品种所属的纽交所位于"America/New_York"时区(UTC-4/-5)。 - 虽然我们的示例图表使用60分钟时间框架,但图表末端的表格和标签显示最后一根K线仅在开盘后30分钟(1,800,000毫秒)收盘。这是因为图表将K线与交易时段开收盘时间对齐。交易时段最后一根K线在时段结束时收盘,新时段开始时新K线开盘。我们60分钟图表的标准交易时段(RTH)从09:30持续到16:00(6.5小时)。图表从时段开盘时间开始尽可能多地划分60分钟K线,最后仅剩30分钟形成最后一根K线。
需要特别注意,与time变量在不同图表类型中表现一致不同,time_close在基于时间和非基于时间的图表上表现不同。
基于时间的图表中,K线通常在交易时段内以规律、可预测的时间开盘和收盘。由于这种可预测性,time_close可以准确表示基于时间图表上未完成K线的预期收盘时间,如上例中最后一根K线所示。
相比之下,tick图表和基于价格的图表中的K线覆盖不规则时间间隔。tick图表基于数据源中的连续tick构建K线,基于价格的图表则基于显著价格变动构建K线。新tick或价格变动出现的时间是不可预测的。因此,这些图表实时K线的time_close值为na。
以下脚本使用time和time_close变量与str.tostring()和str.format_time()创建包含K线开盘和收盘UNIX时间戳及格式化日期时间表示的字符串,并在每根K线的高低价位置显示标签。
当应用于基于价格变动形成新K线时,标签在所有历史K线上显示正确结果。但最后一根K线的time_close值为na,因为未来收盘时间不可预测。因此,该K线的收盘时间标签显示"NaN"时间戳和错误的日期时间:

Mine Script®
已复制
请注意:
- 脚本最多绘制50个标签,因为我们没有在indicator()声明语句中指定
max_labels_count参数。 - str.format_time()函数在计算中将
na值替换为0,这就是为什么它在最后一根K线上返回错误的日期时间“string”。时间戳0对应UNIX纪元(UTC时间1970年1月1日00:00:00)。然而,str.format_time()调用没有指定timezone参数,因此它以交易所时区表示纪元的日期和时间,当时该时区比UTC慢5小时。 - time_close()函数(返回指定时间框架和给定交易时段内K线的收盘时间戳)在基于tick和基于价格的图表的实时K线上同样返回
na值。
time_tradingday
time_tradingday变量保存一个UNIX时间戳,表示当前K线最后交易时段中最后一个交易日的开始时间(00:00 UTC)。它主要用于基于时间的图表上,对具有跨日历日夜市的交易品种进行日期和时间计算。
在“1D”及以下时间周期上,即使K线在前一日开盘和收盘,time_tradingday时间戳也对应交易时段结束当天的开始时间。例如,“EURUSD”的“周一”交易时段在交易所时区从周日17:00开始,到周一17:00结束。该交易时段内所有日内K线的time_tradingday值都代表周一00:00 UTC。
在高于“1D”的时间周期上(可能包含多个交易时段),time_tradingday保存代表该K线最后交易时段中最后一个日历日开始的时间戳。例如,在“EURUSD,1W”图表上,该时间戳通常代表当周最后一个交易日(周五)00:00 UTC。
下方脚本演示外汇品种中time_tradingday与time变量的差异。它在每根K线上绘制标签,显示包含变量UNIX时间戳及格式化日期时间的字符串,并使用dayofmonth()函数计算两个时间戳对应的UTC日历日,当计算结果不匹配时高亮背景。
当应用于“FXCM:EURUSD”图表的“3h”(“180”)时间周期时,脚本会高亮每个交易时段第一根K线的背景,因为每个交易时段都在前一个日历日开始。使用time的dayofmonth()调用计算交易时段第一根K线的开盘日,而使用time_tradingday的调用则计算交易时段结束日。

Mine Script®
已复制
请注意:
- str.format_time()和dayofmonth()调用使用
"UTC+0"作为timezone参数,这意味着结果表示的是没有UTC偏移的日历时间值。在截图中,第一根K线在UTC时间21:00开盘,即交易所时区("America/New_York")的17:00。 - 格式化字符串显示
"GMT"作为时区缩写,在此上下文中等同于"UTC+0"。 - 每个交易时段内所有三小时K线的time_tradingday值都相同,即使是前一个UTC日历日开盘的首根K线也是如此。只有当新交易时段开始时,该时间戳才会改变。
timenow
timenow变量保存一个表示脚本当前时间的UNIX时间戳。与其他保存UNIX时间戳的变量不同,timenow序列中的值对应的是脚本执行时的时间,而非特定K线或交易日的时间。
Mine脚本在每根历史K线上仅执行一次,所有历史执行都发生在脚本首次加载到图表时。因此,timenow值在历史K线上相对一致,在整个序列中仅偶尔出现毫秒级的变化。相反,在实时K线上,脚本会随着数据源的每次更新而执行(每根K线可能发生多次)。每次新执行时,timenow值都会在最新K线上更新以反映当前时间。
注意
由于timenow仅在脚本执行后更新,其值并不总是与图表下方显示的连续时间完全对应。当实时数据源没有新更新时,图表上的脚本将保持空闲状态,此时该变量的时间戳不会发生变化。
该变量在实时K线上最为实用,程序员可将其用于追踪最近脚本执行的时间,计算未完成K线内经过的时间,基于K线更新控制绘图等。
以下脚本检查最新图表K线上的timenow值,并用其分析实时K线更新情况。当脚本首次到达最后一根K线时,它使用varip关键字声明三个变量来保存:
- 最新的timenow值
- K线更新之间的总时间
- 更新总次数
脚本使用这些值计算更新之间的平均毫秒数,将其与当前执行的时间戳、交易所时区的格式化日期时间以及当前K线更新次数一起显示在标签中:

Mine Script®
已复制
请注意:
- 当K线未确认(未收盘)时,标签显示为蓝色,表示可能还有后续更新。当K线确认(收盘)后,标签变为灰色。
- 虽然我们将图表时区设置为与交易所时区一致,但未收盘K线标签中的格式化时间与图表下方显示的时间并不总是完全一致。这是因为脚本仅在每次执行时记录新时间戳,而图表下方的时间是持续更新的。
- varip关键字指定变量在发生新更新时不会回滚到序列中最后提交的值。这一特性使脚本能够使用变量来追踪未收盘K线上timenow的变化。
- 在脚本执行过程中,未收盘实时K线上timenow的更新不会影响已确认K线的记录时间戳。但是,重新加载图表后历史序列会发生变化(重绘),因为timenow引用的是脚本当前时间,而非特定K线的时间。
基于日历的变量
year、month、weekofyear、dayofmonth、dayofweek、hour、minute和second变量保存基于日历的“int”值,这些值根据当前K线开盘时间计算,并以交易所时区表示。这些变量引用的值与基于日历的函数使用默认timezone参数和time作为time参数时返回的值相同。例如,year变量保存的值与year(time)调用返回的值相同。
程序员可以使用这些基于日历的变量实现多种功能,例如:
- 识别K线的开盘日期和时间
- 将变量传递给timestamp()函数以计算UNIX时间戳
- 检测数据源中特定日期/时间值或范围的出现
这些变量最常见的用例之一是检查日期或时间范围,以控制脚本何时显示可视化效果或执行计算。以下简单示例通过检查year变量来确定何时绘制可见值。如果年份为2022年或更高,则脚本绘制K线的收盘价;否则绘制na:

Mine Script®
已复制
当使用这些变量来隔离特定日期或时间(而非范围)的条件判断时,必须考虑以下关键因素:由于图表时间框架、K线开盘时间或交易品种的活跃时段,某些条件可能无法检测到特定值的出现。
举例说明,假设我们需要检测图表上每月第一个日历日的出现。直观做法可能是简单地检查dayofmonth值是否等于1。然而,此条件仅能识别在当月首日开盘的K线。某些图表上的K线可能跨月开盘和收盘。此外,若市场在当月首日休市,图表K线可能完全不包含该日期。因此,我们必须创建额外条件来应对这些场景,以准确识别图表上每个月的首日。
以下脚本使用dayofmonth和month变量,结合month()函数,创建了三种检测月初首日的条件:
- 第一种条件检测K线是否在当月首日开盘
- 第二种条件检查K线是否跨月开盘和收盘
- 第三种条件检查图表是否完全跳过该日期
脚本通过绘制显示K线开盘日期的标签,并用不同颜色高亮背景来可视化每种条件的触发情况:

Mine Script®
已复制
请注意:
- 脚本调用month()函数时使用time_close作为
time参数,为containsFirst条件计算每根K线的收盘月份。 dayofweek.*命名空间包含保存每个可能dayofweek值的变量,例如dayofweek.sunday保存常量值1,dayofweek.saturday保存常量值7。脚本在switch结构中将dayofweek与这些变量进行比较,以确定每个标签内显示的星期名称。- 要检测每月时间框架中的第一个开盘时间(严格来说并非日历月的第一天),应使用
ta.change(time("1M")) > 0或timeframe.change("1M"),而非基于这些变量的条件判断。更多信息请参阅测试更高时间框架变化章节。
last_bar_time
last_bar_time变量保存表示最后一根可用K线开盘时间的UNIX时间戳。它与last_bar_index类似,后者引用的是最新K线的索引。在历史K线上,last_bar_time始终引用脚本首次加载到图表时最后一根可用K线的时间值。该变量的值仅在脚本执行过程中新实时K线开盘时才会更新。
以下脚本使用last_bar_time变量获取第一根K线执行时最后一根图表K线的开盘时间戳。它在一个单单元格表格中显示UNIX时间戳和格式化日期时间,该表格仅在第一根K线上创建。当脚本在最后一根可用K线上执行时,它会绘制一个标签,显示K线的时间值及其格式化表示形式以便视觉对比。
如下图所示,两个绘图显示的时间完全相同,验证了last_bar_time在之前的历史K线上正确引用了最后一根K线的时间值:

Mine Script®
已复制
请注意:
- 脚本仅在barstate.islast状态的第一根K线上创建标签,因为该K线的时间值就是last_bar_time在所有历史K线上相等的值。在后续K线上,last_bar_time值会更新为最新实时K线的开盘时间。
- 在脚本执行过程中,实时K线上last_bar_time的更新不会影响历史K线的值。但是,当脚本重新启动时,该变量的序列会重绘,因为last_bar_time始终引用最新可用K线的开盘时间。
syminfo.timezone
syminfo.timezone变量保存一个表示当前交易品种所属交易所时区的时区字符串。该“string”值以IANA标识符表示时区(例如"America/New_York")。所有包含timezone参数的时间函数重载都默认使用syminfo.timezone作为参数。
由于该变量是所有适用时间函数重载的默认timezone参数,除非出于代码风格考虑,否则无需显式使用它作为参数。不过,程序员可以通过以下方式使用该变量:
- 在Mine日志或绘图中显示“string”以检查交易所时区的IANA标识符
- 将该值与其他时区字符串比较以创建基于时区的条件逻辑
- 通过
request.*()函数调用获取其他交易品种的交易所时区
时间函数
Mine Script提供多个内置函数用于获取、计算和表示时间值:
- time()和time_close()函数允许脚本获取指定时间框架下交易时段内K线开盘和收盘的UNIX时间戳,无需使用
request.*()函数调用。 - year()、month()、weekofyear()、dayofmonth()、dayofweek()、hour()、minute()和second()函数从UNIX时间戳计算基于日历的值,并以指定时区表示。
- timestamp()函数根据指定的日历日期和时间计算UNIX时间戳。
- str.format_time()函数将UNIX时间戳格式化为人类可读的日期/时间“string”,以指定时区表示。下文格式化日期和时间章节提供使用此函数格式化时间戳的详细信息。
- input.time()函数返回与用户指定日期和时间对应的UNIX时间戳,input.session()函数返回与用户指定开始和结束时间对应的有效时段字符串。更多关于这些函数的信息,请参阅输入页面的时间输入和时段输入章节。
time()和time_close()函数
time()和time_close()函数返回表示指定时间框架下K线开盘和收盘时间的UNIX时间戳。这两个函数都可以根据特定时区下的给定交易时段来筛选返回值。它们各自具有以下函数调用方式:
functionName(timeframe, bars_back) → series int
functionName(timeframe, session, bars_back) → series int
functionName(timeframe, session, timezone, bars_back) → series int其中:
functionName表示函数标识符timeframe参数接受时间框架字符串。若参数为 timeframe.period 或空字符串,函数将使用脚本的主时间框架session参数接受定义交易时段开始和结束时间的字符串(如"0930-1600"),以及适用的日期(如":23456"表示周一至周五)。若未指定日期,则默认适用于所有工作日。函数仅返回该交易时段内K线的时间戳,时段外的K线返回na。若session参数为空字符串或未指定,函数将使用交易品种的默认交易时段信息timezone参数接受有效的时区字符串,用于定义指定交易时段的时区。它不会改变返回的UNIX时间戳的含义,因为时间戳本身与时区无关。若未指定timezone参数,函数将使用交易所时区(syminfo.timezone)bars_back参数接受整型值,指定返回哪个K线的时间戳。若值为正数,函数返回相对于当前K线向前偏移指定数量K线的时间戳;若为负数且大于等于-500,则返回未来K线的预期时间戳。默认值为0 与 time()和time_close() 变量类似,这些函数在基于时间和非基于时间的图表上表现不同。
基于时间的图表中,K线在可预测的时间开盘和收盘。time_close()无法计算非基于时间图表上实时K线的预期收盘时间,这些K线将返回na。同样,当bars_back为负值时,time()函数也无法准确计算这些图表上未来实时K线的预期开盘时间。具体示例可参考前文第二个案例,该示例脚本若使用time_close("")调用替代time_close变量,在基于价格的图表上会表现出相同行为。
time()和time_close()函数的典型应用场景包括:
- 测试在
session和timezone参数定义的特定交易时段内开盘或收盘的K线 - 测试指定更高时间框架上的变化或测量时间差
测试交易时段
time()和time_close()函数的session和timezone参数定义了它们能返回非na值的交易时段。如果函数调用引用的K线在给定时区的定义时段内开盘/收盘,则返回该K线的UNIX时间戳,否则返回na。程序员可以将返回值传递给na()函数来识别哪些K线在指定时间区间内开盘或收盘,这对于基于交易时段的计算和逻辑判断很有帮助。
这个简单脚本用于识别图表时间框架上,在交易所时区内任意交易日11:00至13:00之间开盘的K线。它调用time()函数,timeframe参数设为timeframe.period,session参数设为"1100-1300"时段字符串,然后通过na()函数验证返回值是否为na。当返回值非na时,脚本高亮图表背景,表示该K线在目标时段内开盘:

Mine Script®
已复制
请注意:
- 由于 syminfo.timezone 是默认的时区参数,因此 time() 调用中的
session参数表示交易所时区内的一个时段。 - 交易时段字符串以
"HHmm-HHmm"格式表示开始和结束时间,其中"HH"为两位小时数,"mm"为两位分钟数。交易时段字符串也可指定适用的工作日。然而 time() 调用的session参数 ("1100-1300") 未包含此信息,因此该交易时段被视为每日有效。详见交易时段说明页。
在 time() 和 time_close() 调用中使用交易时段字符串时,必须理解此类字符串定义的是特定时区的起止时间。同一小时和分钟数值在不同地区对应的本地时间,在 UNIX 时间轴上可能并不对应相同的时间点。因此当使用不同 timezone 参数调用这些函数时,由于指定时区字符串改变了 session 参数中本地时间的含义,函数可能在不同时间返回非空(non-na)时间戳。
此示例演示了 time() 函数调用中 timezone 参数如何影响 session 参数。脚本通过基于输入参数的 time() 调用计算 opensInSession 条件。交易时段参数的 session 输入包含四个预设选项:"0000-0400"、"0930-1400"、"1300-1700" 和 "1700-2100"。定义 timezone 参数的字符串输入包含四个代表不同 UTC 时区偏移的 IANA 时区选项:"America/Vancouver" (UTC-7/-8)、"America/New_York" (UTC-4/-5)、"Asia/Dubai" (UTC+4) 和 "Austrailia/Sydney" (UTC+10/+11)。
对于任意选定的 sessionInput 值,更改 timezoneInput 值将改变指定交易时段的时区。脚本在不同时区选择下高亮显示不同 K 线,这是因为与 UNIX时间戳不同,相同本地小时和分钟数值在各时区对应的绝对时间存在差异:

Mine Script®
已复制
请注意:
测试更高时间框架变化
time()和time_close()函数的timeframe参数用于指定计算中所用K线的时间框架,使脚本无需调用request.*()函数即可获取比当前图表时间框架更高层级的开盘/收盘UNIX时间戳。
程序员可利用更高时间框架(HTF)K线的开盘/收盘时间戳来检测时间框架变化。常见方法是在基于时间的图表上,使用固定的timeframe参数调用time()或time_close(),并通过ta.change()函数测量返回值单根K线的变化。仅当HTF K线开盘时,结果才会返回非零值。还可通过比较当前K线的time()值与上一根K线的time_close()值,检测该时点是否存在时间缺口。当当前K线的开盘时间戳大于上一根K线的收盘时间戳时,即存在缺口。
下方脚本调用time("1M")获取"1M"时间框架下当前K线的开盘UNIX时间戳。通过检测时间戳的ta.change()返回值是否大于0,来判断该时间框架K线是否开盘。每次条件触发时,脚本会检查当前开盘时间是否大于前一根K线的time_close("1M")值,从而判断HTF K线开盘时是否存在时间缺口。
脚本绘制包含格式化"1M"开盘时间的标签,用于标记月度K线起始位置。若月度K线开盘时与前一根收盘时间无缺口,则绘制蓝色标签;若存在缺口则绘制红色标签。此外,若"1M"开盘时间与图表K线开盘时间不匹配,脚本会在标签中显示该K线格式化时间以供对比:

Mine Script®
已复制
请注意:
- 在 time()或time_close() 调用结果上使用 ta.change() 并非检测更高时间框架变化的唯一方法。timeframe.change() 函数是等效但更便捷的选择,特别适用于不需要在其他计算中使用 HTF K 线 UNIX 时间戳的脚本,因为它直接返回布尔值而无需额外代码。
- 检测到的月度开盘时间并不总是对应日历月的第一天,而是对应分配给
"1M"K线的首个时间点,该时间点可能晚于日历月首日。对于具有隔夜交易时段的品种(如示例图表中的"XAUUSD"),"1M"K线开盘时间甚至可能早于日历月首日。 - 有时 HTF K 线的指定开盘时间可能与任何图表 K 线的开盘时间都不一致,这就是为什么
time == time("1M")等其他条件无法稳定检测新月度 K 线的原因。例如在我们的"XAUUSD"图表中,"1M"开盘时间2023-12-31T17:00:00-0500与"1D"时间框架上的任何开盘时间都不匹配,此后首个可用的"1D"K线开盘时间为2024-01-01T17:00:00-0500。
基于日历的函数
函数 year()、month()、weekofyear()、dayofmonth()、dayofweek()、hour()、minute() 和 second() 用于从 UNIX 时间戳计算基于日历的整型值。与始终基于当前 K 线开盘时间戳返回交易所日历值的日历变量不同,这些函数可以为任何有效时间戳返回日历值,并按照指定时区表达结果。
这些基于日历的函数均具有以下两种调用方式:
functionName(time) → series int
functionName(time, timezone) → series int其中:
functionName表示函数名称标识符time参数接受一个整型 UNIX 时间戳,函数将为其计算对应的日历值timezone参数接受时区字符串,用于指定返回值的时区。若未指定timezone参数,函数将使用交易所时区(syminfo.timezone)
与返回 UNIX 时间戳的函数不同,基于日历的函数会根据不同时区返回不同的整型结果,因为日历值代表特定地区的本地时间组成部分。
例如,下方简单脚本使用两次 dayofmonth() 调用来计算每根 K 线在交易所时区和"Australia/Sydney"时区的开盘日。脚本将两次调用的结果绘制在单独面板中以供对比:

Mine Script®
已复制
请注意:
- 第一个 dayofmonth() 调用计算的是 K 线在交易所时区的开盘日,因其未包含
timezone参数。该调用返回值与 dayofmonth 变量引用的值相同。 - 本示例品种的交易所时区为
"America/New_York",标准时间采用 UTC-5,夏令时(DST)采用 UTC-4。而"Australia/Sydney"时区标准时间采用 UTC+10,夏令时采用 UTC+11。但悉尼的夏令时时段与纽约不同,因此该时区比交易所时区快14、15或16小时(具体取决于季节)。在我们的"1D"图表上,当时差至少达到15小时时,两条曲线会出现分歧,因为K线在交易所时区09:30开盘,而15小时后的00:30已属次日历日。
需重点理解:虽然基于日历的函数调用中的 time 参数代表单一绝对时间点,但每个函数仅返回时间戳所包含的部分日期时间信息。因此,基于日历的函数返回值并不直接对应唯一时间点,基于单个日历值的条件可能适用于多根K线。
例如,本脚本使用 timestamp() 函数从日期字符串计算 UNIX 时间戳,并通过 dayofmonth() 函数计算该时间戳在交易所时区对应的日历日。脚本将每根K线的开盘日与计算日进行比较,当两者相等时高亮背景:

Mine Script®
已复制
请注意:
- timestamp() 调用将其参数视为 UTC 日历日期,因其
dateString参数未指定时区信息。但 dayofmonth() 调用计算的是交易所时区的日期。本示例品种的交易所时区为"America/New_York" (UTC-4/-5),因此图表返回值为 28 而非 29。 - 该脚本会高亮图表中每月第28天开盘的所有K线,而非特定一根K线,因为 dayofmonth() 函数返回值本身并不代表特定时间点。
- 本脚本会高亮与时间戳计算所得月份日期相符的开盘K线。但某些月份该日并无交易活动,例如图表中未显示2025年6月28日的高亮标记,因纳斯达克周日休市。
与基于日历的变量类似,这些函数同样适用于检测特定日期/时间及图表中的日历变更。下方示例使用 year()、month()、weekofyear() 和 dayofweek() 函数对 time_close 时间戳进行计算,创建条件来检测当前K线是否为新年度、新季度、新月份、新周及新日的首根收盘K线。脚本通过绘制形状、标签及背景色在图表上可视化这些条件:

Mine Script®
已复制
请注意:
- 本脚本的条件检测的是每个日历单位变更后首根收盘K线。各条件成立的K线会随图表数据而变化。例如,若某月首个日历日没有K线收盘,
closeInNewMonth条件可能会在该日之后的首根收盘K线成立。 - 如需检测特定时间框架(而非严格日历变更)的新K线起始时点,请检查 time() 或 time_close() 调用返回值的 ta.change() 是否为非零值,或使用 timeframe.change() 函数。更多信息请参阅前文相关章节。
timestamp()
timestamp() 函数用于将指定日历日期时间转换为 UNIX 时间戳,具有以下三种调用方式:
timestamp(year, month, day, hour, minute, second) → simple/series int
timestamp(timezone, year, month, day, hour, minute, second) → simple/series int
timestamp(dateString) → const int前两个调用方式包含接受“int”类型参数的year、month、day、hour、minute和second参数,用于定义日历日期和时间。使用这两个调用方式中任一调用方式的timestamp()调用必须包含year、month和day参数。其他参数为可选参数,默认值均为0。根据所指定参数的类型限定,这两个调用方式可以返回“simple”或“series”类型的值。
前两个调用方式的主要区别在于timezone参数,该参数接受一个时区字符串,用于确定其他参数所指定日期和时间的时区。如果使用“int”类型日历参数的timestamp()调用不包含timezone参数,则默认使用交易所时区(syminfo.timezone)。
第三个调用方式仅包含一个dateString参数,该参数接受表示有效日历日期的“string”类型值(例如“20 Aug 2024”)。该值也可以包含一天中的时间和时区(例如“20 Aug 2024 00:00:00 UTC+0”)。如果dateString参数未指定具体时间,timestamp()调用将视为00:00(午夜)。
与其他两个调用方式不同,第三个调用方式的默认时区为GMT+0。它不会默认使用交易所时区,因为它直接从dateString解析时区信息。此外,第三个调用方式是唯一返回“const int”类型值的调用方式。如输入页面中的时间输入部分所示,程序员可以将此重载的返回值用作input.time()函数调用中的defval参数。
使用timestamp()函数时,理解时区信息如何影响其计算至关重要。特定日历日期所表示的绝对时间点取决于其时区,因为不同时区中的相同日期和时间可能对应自UNIX纪元以来不同的时间量。因此,更改timestamp()调用中日历日期和时间的时区可能会改变其返回的UNIX时间戳。
以下脚本比较了四个不同timestamp()调用的结果,这些调用评估了不同时区中的2021-01-01日期。第一个timestamp()调用未在其dateString参数中指定时区信息,因此将其视为UTC日历日期。第四个调用也评估了UTC中的日历日期,因为它包含“UTC0”作为timezone参数。第二个timestamp()调用使用上面列出的第一个调用方式,意味着它使用交易所时区,第三个调用使用第二个调用方式,并以“America/New_York”作为timezone参数。
脚本绘制了一个表格,其中行显示每个timestamp()调用、其分配的变量、计算出的UNIX时间戳以及时间的格式化表示。如下面的“OANDA:XAUUSD”图表所示,第一行和第四行表格显示的时间戳与第一行和第三行不同,导致最后一列中的格式化字符串也不同:

Mine Script®
已复制
请注意:
- 格式化日期时间字符串以交易所时区显示结果,因为str.format_time()函数默认使用syminfo.timezone作为时区参数。在我们的示例图表中,格式化值显示偏移字符串
“-0500”,因为纳斯达克的时区(“America/New_York”)在标准时间遵循UTC-5。 - 第一行和第四行的格式化字符串显示2021年1月1日之前五小时的日期和时间,因为timestamp()调用以UTC时区计算日期,而str.format_time()调用使用的时区比UTC慢五小时。
- 在我们的图表上,第二行和第三行具有匹配的时间戳,因为两个对应的timestamp()调用都在
“America/New_York”时区计算日期。如果我们将脚本应用于具有不同交易所时区的品种,这两行将显示不同的结果。
格式化日期和时间
程序员可以使用 str.format_time() 函数将 UNIX 时间戳格式化为人类可读的日期和时间,并以特定时区显示。该函数具有以下签名:
str.format_time(time, format, timezone) → series string其中:
time参数指定要转换为可读时间的“int”类型 UNIX 时间戳format参数接受由格式化标记组成的“string”类型值,这些标记决定返回的信息内容。若函数调用未包含format参数,则默认使用 ISO 8601 标准格式:"yyyy-MM-dd'T'HH:mm:ssZ"。有效标记及其表示的含义请参阅下表timezone参数决定格式化结果的时区,接受 UTC 或 IANA 格式的时区字符串。若未指定timezone参数,则使用交易所时区(syminfo.timezone)
通用函数 str.format() 也可将 UNIX 时间戳格式化为可读日期和时间,但该函数无法以不同时区表示时间信息,始终以 UTC+0 时区输出。因此使用该函数格式化时间戳常导致错误做法,例如通过数学运算修改时间戳来尝试表示其他时区的时间。但 UNIX 时间戳是独立于时区的特定时间点的唯一表示,修改时间戳会改变其表示的绝对时间,而非同一时间在不同时区的表达。
str.format_time() 函数没有此限制,它能正确计算任意时区的日期时间而无需改变 UNIX 时间戳的含义。此外,与 str.format() 不同,该函数专门针对时间值处理进行了优化。因此我们建议程序员使用 str.format_time() 而非 str.format() 来格式化 UNIX 时间戳。
str.format_time() 调用的 format 参数决定其返回值包含的时间信息。函数将参数中的字符和序列视为格式化标记,这些标记作为返回日期/时间“string”中的占位符。下表列出了有效格式化标记及其含义:
| 标记符 | 表示内容 | 说明及示例 |
|---|---|---|
"y" | 年份 | 使用 "yy" 表示年份的最后两位数字(例如 "00"),或 "yyyy" 表示完整的年份数字(例如 "2000") |
"M" | 月份 | 大写 "M" 表示月份,不要与小写 "m"(分钟)混淆使用 "MM" 表示带前导零的两位月份数字(例如 "01"),"MMM" 表示月份的三字母缩写(例如 "Jan"),"MMMM" 表示完整的月份名称(例如 "January") |
"d" | 星期 | 小写 "d"表示星期几日期( "1" 至 "7")使用 "dd" 表示星期几(1-7)的占位符。可以使用 dayofweek() 计算该值 |
"D" | 月份中的日 | 大写"D"表示月份中的日(1-31)"DD":两位日期(如"01")使用 "DDD" 或 "DDDD" 表示是否带前导零的两位或三位的年积日 |
"w" | 年中的周 | 小写 "w"表示年中的周数( "1" 至 "53")使用 "ww" 表示带前导零的两位周数 |
"W" | 月中的周 | 大写 "W"表示月中的周数( "1" 至 "5") |
"a" | AM/PM 后缀 | 小写 "a"如果时间在中午之前则包含 "AM",否则包含 "PM" |
"h" | 12小时制小时 | 小写 "h"表示从 "0" 到 "11" 的小时数使用 "hh" 表示带前导零的两位小时数 |
"H" | 24小时制小时 | 大写 "H"表示从 "0" 到 "23" 的小时数使用 "HH" 表示带前导零的两位小时数 |
"m" | 分钟 | 小写 "m" 表示分钟,不要与大写 "M"(月份)混淆使用 "mm" 表示带前导零的两位分钟数 |
"s" | 秒 | 小写 "s" 表示秒,不要与大写 "S"(毫秒)混淆使用 "ss" 表示带前导零的两位秒数 |
"S" | 毫秒 | 大写 "S"表示毫秒( "0" 至 "999")使用 "SS" 或 "SSS" 表示带前导零的两位或三位毫秒数 |
"Z" | 时区(UTC 偏移) | 大写 "Z"以 "HHmm" 格式表示 UTC 偏移值,前面带符号(例如 "-0400") |
"z" | 时区(缩写或名称) | 小写 "z"单个 "z" 包含时区的缩写(例如 "EDT")使用 "zzzz" 表示时区的全名(例如 "Eastern Daylight Time")这不是 IANA 标识符的占位符。使用 syminfo.timezone 获取交易所时区的 IANA 表示 |
":", "/", "-", ".", ",", "(", ")", " " | 分隔符 | 这些字符是格式化标记的分隔符 在格式化文本中按原样显示(例如 "01/01/24", "12:30:00", "Jan 1, 2024")其他字符也可以作为分隔符,但列出的这些是最常见的 |
"'" | 转义字符 | 用两个单引号括起来的字符在结果中按原样显示,即使它们原本是格式化标记 例如 "'Day'" 在结果字符串中显示为 'Day',而不是列出年中的日、AM/PM 后缀和年份 |
以下示例演示了不同格式化标记如何影响 str.format_time() 函数的结果。该脚本使用不同的 format 参数调用该函数,从 time、timenow 和 time_close 时间戳创建日期/时间字符串,并在最后一根K线上以表格形式显示每个格式值及其对应的格式化结果:

Mine Script®
已复制
时间差的表示方法
每个UNIX时间戳都代表从固定历史时间点(纪元)开始的绝对时间差。所有UNIX时间戳参考的特定纪元是UTC时间1970年1月1日午夜。程序员可以使用str.format_time()函数将UNIX时间戳格式化为可读的日期时间字符串,因为该函数在日期和时间计算中使用的是与UNIX纪元的时间差。
相比之下,两个非零UNIX时间戳之间的差值表示从一个绝对时间点到另一个绝对时间点所经过的毫秒数。如果运算中两个时间戳的值都不为0(对应于UNIX纪元),则该差值并不直接指向UNIX时间中的特定时间点。
程序员可能希望将两个UNIX时间戳之间的毫秒差表示为其他时间单位,如秒、天等。有些人可能认为他们可以使用这个差值作为str.format_time()调用的time参数来实现这一结果。然而,该函数总是将其time参数视为从UNIX纪元开始经过的时间,以得出特定时区的日历日期/时间表示。它不直接表示时间差。因此,尝试用str.format_time()格式化时间戳差值而非时间戳会导致非预期的结果。
例如,以下脚本计算当前执行时间(timenow)与"1M"K线收盘时间(time_close("1M"))之间的毫秒差,用于月度倒计时显示。它尝试使用str.format_time()以另一种格式表示时间差。脚本在表格中显示函数调用的结果,以及原始的毫秒差值(timeLeft)和时间戳的格式化日期时间表示。
如下所示,表格正确显示了格式化时间戳和timeLeft值的结果。然而,格式化后的时间差显示为"1970-01-10T09:00:31-05:00"。尽管timeLeft值本应表示时间戳之间的差值而非特定时间点,但str.format_time()函数仍将该值视为UNIX时间戳。因此,它创建了一个"字符串",将该值表示为UTC-5时区的日期和时间:

Mine Script®
已复制
要正确表示两个时间戳之间的差值(以其他时间单位表示),程序员必须编写代码来计算经过的时间单位数,而不是错误地将差值格式化为特定的日期或时间。
表示时间差所需的计算取决于所选择的时间单位。以下部分将说明如何将毫秒差表示为周及更小单位,以及月及更大单位。
周及更小单位
周及更小时间单位(天、小时、分钟、秒和毫秒)的时间跨度是固定的,这些单位之间存在以下换算关系:
- 1周 = 7天
- 1天 = 24小时
- 1小时 = 60分钟
- 1分钟 = 60秒
- 1秒 = 1000毫秒
基于这个关系,程序员可以通过定义每个单位包含的毫秒数来表示这些时间跨度。例如,由于1小时=60分钟,1分钟=60秒,1秒=1000毫秒,因此每小时的毫秒数为60×60×1000=3600000。
程序员可以使用基于每个时间单位毫秒数的模运算,来计算两个UNIX时间戳差值所包含的完整周数、天数及更小单位的时间跨度。计算过程如下(从最大的时间单位开始):
- 计算当前时间单位对应的毫秒数
- 用剩余的毫秒差除以该值并向下取整,结果表示该时间间隔内完整的单位数量
- 将除法运算的余数作为新的剩余毫秒差
- 按照单位从大到小的顺序,对每个时间单位重复步骤1-3
以下脚本通过自定义的formatTimeSpan()函数实现了这个过程。该函数接受两个定义起止点的UNIX时间戳,其布尔型参数控制是否计算时间范围内包含的周数或更小单位。函数首先计算两个时间戳之间的毫秒差,然后计算该差值包含的完整单位数量,并将结果格式化为字符串。
脚本调用formatTimeSpan()函数来计算两个不同时间输入值之间以选定时间单位表示的差值,并在表格中显示结果字符串以及起止时间的格式化表示:

Mine Script®
已复制
请注意:
- 用户自定义函数使用math.floor()将每个除法结果向下取整为最接近的“int”值,以获取时间间隔内完整的单位数量
- 在每次除法运算后,函数使用模赋值运算符(%=)获取余数,并将该值赋给
timeDifference变量 - 此过程会对每个选定的时间单位重复执行
如上图所示,计算结果以混合时间单位显示时间差。通过切换“bool”类型输入参数,用户也可以单独计算特定单位的时间差。例如,下图展示了仅启用“毫秒”输入参数后的计算结果:

月及更大单位
与周及更小单位不同,月及更大单位的时间长度会因日历规则而异。例如,一个月可能包含28、29、30或31天,而一年可能包含365或366天。
部分程序员倾向于使用前文所述的模运算方法,通过为这些不规则单位设定近似长度来计算UNIX时间戳之间的大单位时间差。这种方法通常采用以下两种定义方式之一:
- 通用长度:例如普通年=365天,普通月=30天 - 平均长度:例如平均年=365.25天(考虑闰年),平均月=30.4375天
基于近似单位的计算会产生粗略的时间差估算。此类估算在表达较短时长时通常可行,但其精度会随差值增大而降低,逐渐偏离实际流逝时间。
因此,若需精确表达月及更大单位的时间差,需采用不同于上述流程的计算方法。要精确计算相隔的月数、年数等大单位,必须基于每个单位实际跨度而非近似值,即需考虑闰年与月份天数差异。
下方进阶示例包含一个自定义函数formatTimeDifference(),用于计算两个UNIX时间戳之间相隔的年、月、日及更小单位。
该函数沿用前文流程计算天及更小单位,而对长度不规则的月与年,则通过while循环迭代日历月份:每次循环递增月/年计数器,并从天数中扣除当前月份的天数。循环结束后,函数会调整年、月、日计数器以处理时间戳之间的不足整月部分。最终通过str.format()调用这些计数器,生成包含计算值的格式化“字符串”。
脚本调用此formatTimeDifference()函数,计算两个不同输入时间之间相隔的年、月、日、时、分、秒及毫秒,并将结果显示在标签中:

Mine Script®
已复制
需注意:
- 脚本通过用户自定义函数
daysPerMonth()确定每月天数。该函数根据月份编号及所属年份判断当月有28、29、30还是31天,其计算会考虑闰年情况。闰年判定规则为:年份能被4或400整除但不能被100整除。 - 在while循环开始前,函数会从初始天数中扣除起始月份的不完整天数,使计数器与新月份起始对齐。循环结束后重新加回扣除的天数以校正不完整月份。若起始日(
startDay)处于起始月份(startMonth)的前半段,则根据起始月份的天数调整月/年计数器;否则根据结束月份(endMonth)的天数调整。