ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Metabase `now` 表达式:获取当前时间并构建实时条件逻辑

Metabase `now` 表达式:获取当前时间并构建实时条件逻辑 Metabasenow表达式获取当前时间并构建实时条件逻辑【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabasenow是 Metabase 自定义表达式Custom Expressions中的时间函数返回基于 Metabase报表时区report timezone的当前日期时间。本文以 now 官方文档 为主体结合当前仓库的 MBQL 表达式 schema、SQL 驱动编译链路与测试用例讲解now的数据类型、时区语义、实战条件逻辑写法以及与 SQL / 电子表格 / Python 的等价实现。什么是nownow是一个无参数函数返回当前时刻的日期时间datetime。关键在于这个当前时刻不是你的本地时间而是 Metabase报表时区下的当前时间。now()例如在 Metabase 查询编辑器的自定义表达式框中输入now()即可在结果中生成一列当前时间。报表时区是什么Metabase 管理员可以在实例设置中配置默认的报表时区Report Timezone详见 配置默认实例报表时区。所有使用now的表达式都会以该时区为基准计算当前时间如果管理员已设置报表时区now返回该时区下的当前时间如果管理员未设置报表时区now回退到数据库的时区。这一行为在文档的 SQL 章节 中有更具体的说明。实战用now构建条件状态列假设你有一份项目任务数据希望根据任务的开始时间Start与截止时间Deadline自动计算任务状态。为便于说明假设今天是 2022 年 11 月 22 日 12:00:00TaskStartDeadlineStatusDraftNovember 1, 2022, 12:00:00November 30, 2022, 12:00:00In progressReviewNovember 15, 2022, 12:00:00November 19, 2022, 12:00:00Needs extensionEditNovember 22, 2022, 12:00:00November 22, 2022, 12:00:00DUE RIGHT NOW!标记进行中的任务任务处于进行中意味着当前时间在开始之后、截止之前now() [Start] AND now() [Deadline]标记需要延期的任务如果当前时间已经超过截止时间任务需要申请延期now() [Start] AND now() [Deadline]标记此刻到期的任务如果你接入的是实时数据想找出恰好在这秒钟到期的任务一个肾上腺素飙升的玩法now() [Deadline]注意now() [Deadline]只有在数据实时刷新、且时间戳精度与now完全对齐时才可能命中实际使用中更多是演示性质的写法。用case组合三种状态将上述三种情况整合到一列Status中使用case表达式按顺序判断case(now() [Start] AND now() [Deadline], In progress, now() [Start] AND now() [Deadline], Needs extension, now() [Deadline], DUE RIGHT NOW!)case按分支自上而下求值命中第一个为真的条件即返回对应结果。更多case的用法可参考 case 表达式文档。数据类型now的返回值类型如下数据类型是否由now()返回String❌Number❌Timestamp✅Boolean❌JSON❌具体来说如果数据库支持时区now返回timestamp with time zone带时区的时间戳否则返回timestamp without time zone不带时区的时间戳。关于这些类型在 Metabase 中的具体行为参见 Timezones 文档的数据类型章节。源码中的类型定义从当前仓库的 MBQL 表达式 schema 可以印证这一类型声明。在 src/metabase/lib/schema/expression/temporal.cljc 中(mbql-clause/define-tuple-mbql-clause :now :- :type/DateTimeWithTZ)即:now子句被定义为返回:type/DateTimeWithTZ带时区的日期时间类型与文档中返回带时区时间戳的描述一致。前端表达式定义中now的类型同样标注为datetime见 frontend/src/metabase-lib/query/clauses/clauses.ts。限制与时区陷阱时区不一致now可能不是你本地时间的 now如果你所在的时区与 Metabase 报表时区不同now()的结果会与你的本地钟表时间不一致。这是分布式协作环境中非常容易踩的坑——团队成员的当前时间应始终以报表时区为准。与时区不同的列比较如果now需要与一个存储在其他时区的列进行比较例如Deadline列存的是数据库时区的时间两者直接比较会产生错误结果。此时应使用 convertTimezone 将双方统一到同一时区再比较例如convertTimezone(now, UTC, report timezone) convertTimezone([Deadline], UTC, source time zone)源码中的时区对齐实现当前仓库的 Postgres 驱动在编译:now时会处理这种时区对齐场景。src/metabase/driver/postgres.clj 中定义了current-datetime-in-parent-lhs-timezone当now所在过滤条件的左侧是convertTimezone表达式并指定了目标时区时会用TIMEZONE(target-tz, ...)包裹数据库原生的 NOW()使两侧以同一时区的普通时间戳进行比较对应 issue #80155否则原样返回驱动默认的 NOW() 形式(defmethod sql.qp/-honeysql [:postgres :now] [driver _clause] (current-datetime-in-parent-lhs-timezone driver))这说明now并不是简单的取数据库当前时间Metabase 会在 SQL 编译阶段依据上下文做时区语义的调整。底层实现从now()到 SQLnow在 Metabase 查询中会被编译为 MBQL 的:now子句最终由各数据库驱动翻译成对应的 SQL。核心链路位于 src/metabase/driver/sql/query_processor.clj(defmethod -honeysql [:sql :now] [driver _clause] (current-datetime-honeysql-form driver))current-datetime-honeysql-form是一个按驱动派发的多方法src/metabase/driver/sql/query_processor.clj默认实现返回 HoneySQL 的:%now占位符即数据库的当前时间函数如 PostgreSQL 的CURRENT_TIMESTAMP、MySQL 的NOW()(defmethod current-datetime-honeysql-form :sql [_driver] :%now)不同数据库驱动会通过:now true这样的特性标记声明自己支持now表达式例如 Postgres 驱动特性表 与 MySQL 驱动特性表。测试框架中的normal-drivers-with-feature :now也正是依据该特性来圈定可运行now相关测试的驱动集合见 test/metabase/query_processor/date_time_zone_functions_test.clj。测试验证仓库为now提供了系统的集成测试now-test系列覆盖以下场景返回当前时间在nil与America/Los_Angeles两种报表时区下运行[:now]允许 30 秒窗口内的偏差now-test作为日期运算参数datetime-add/datetime-subtract以[:now]为入参now-test-2用于过滤条件[: $date [:now]]统计截止到当前时刻的记录数now-test-3用于datetime-diff[:datetime-diff [:now] [:now] :month]结果为 0now-test-4组合使用now与datetime-diff、date-arithmetics混合嵌套now-test-5。这些测试证明now可以安全地与其他时间函数datetimeadd、datetimediff、datetimesubtract自由组合。相关函数同样的当前时间语义在不同工具中有不同写法——毕竟你更想用自定义表达式解决问题但现在这个词在不同语境下含义并不相同。与 SQL 的对应关系当你在 Metabase 查询构建器query builder中配置筛选、汇总等操作时Metabase 会把这些设置翻译成 SQL 查询并发送到数据库执行。now默认使用 Metabase 的报表时区如果管理员没有设置报表时区则使用数据库的时区。假设你使用 PostgreSQL 数据库报表时区设为 EST 时得到 EST 时区的当前时间SELECT CURRENT_TIMESTAMP AT TIME ZONE EST未设置报表时区时得到 PostgreSQL 数据库时区通常为 UTC下的当前时间SELECT CURRENT_TIME与电子表格Spreadsheet的对应关系电子表格中的NOW()函数获取的是操作系统时区下的当前日期和时间——也就是你电脑或手机上的本地时间这与 Metabase 报表时区的语义不同。与 Python 的对应关系使用pandas模块的pd.Timestamp.now()可以得到当前日期时间的Timestamp对象同样基于操作系统时区。小结Metabase 的now以报表时区为准而电子表格与 Python 以运行环境本地时区为准跨工具对照时需要注意这一差异。延伸阅读自定义表达式总览convertTimezone 表达式case 表达式datetimeadd / datetimesubtract 表达式datetimediff 表达式本地化与报表时区配置Metabase 时区说明【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表