w-dwdata-hub 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/.editorconfig +9 -0
  2. package/.eslintignore +3 -0
  3. package/.eslintrc.js +55 -0
  4. package/.jsdoc +25 -0
  5. package/LICENSE +21 -0
  6. package/README.md +168 -0
  7. package/SECURITY.md +5 -0
  8. package/babel.config.js +16 -0
  9. package/dist/w-dwdata-hub.umd.js +7 -0
  10. package/dist/w-dwdata-hub.umd.js.map +1 -0
  11. package/docs/WDwdataHub.mjs.html +136 -0
  12. package/docs/decodeEntities.mjs.html +129 -0
  13. package/docs/extractDivContent.mjs.html +147 -0
  14. package/docs/fetchAiNewsAggregator.mjs.html +155 -0
  15. package/docs/fetchAisixiang.mjs.html +1038 -0
  16. package/docs/fetchCnyes.mjs.html +260 -0
  17. package/docs/fetchGuancha.mjs.html +1007 -0
  18. package/docs/fetchHackerNews.mjs.html +189 -0
  19. package/docs/fetchMoneydj.mjs.html +251 -0
  20. package/docs/fetchMops.mjs.html +385 -0
  21. package/docs/fetchRSS.mjs.html +160 -0
  22. package/docs/fetchStatementdog.mjs.html +213 -0
  23. package/docs/fetchTaifex.mjs.html +513 -0
  24. package/docs/fetchTpex3insti.mjs.html +278 -0
  25. package/docs/fetchTpexMargin.mjs.html +248 -0
  26. package/docs/fetchTpexStock.mjs.html +199 -0
  27. package/docs/fetchTwDataHoliday.mjs.html +236 -0
  28. package/docs/fetchTwseMargin.mjs.html +253 -0
  29. package/docs/fetchTwseStock.mjs.html +188 -0
  30. package/docs/fetchTwseT86.mjs.html +208 -0
  31. package/docs/fetchWithRetry.mjs.html +376 -0
  32. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  33. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  34. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  35. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  36. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  37. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  38. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  39. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  40. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  41. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  42. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  43. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  44. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  45. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  46. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  47. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  48. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  49. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  50. package/docs/getOptFetch.mjs.html +185 -0
  51. package/docs/global.html +22649 -0
  52. package/docs/htmlToMarkdown.mjs.html +168 -0
  53. package/docs/index.html +84 -0
  54. package/docs/isYmd.mjs.html +114 -0
  55. package/docs/parseIntComma.mjs.html +100 -0
  56. package/docs/safeFilename.mjs.html +102 -0
  57. package/docs/scripts/collapse.js +39 -0
  58. package/docs/scripts/commonNav.js +28 -0
  59. package/docs/scripts/linenumber.js +25 -0
  60. package/docs/scripts/nav.js +12 -0
  61. package/docs/scripts/polyfill.js +4 -0
  62. package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  63. package/docs/scripts/prettify/lang-css.js +2 -0
  64. package/docs/scripts/prettify/prettify.js +28 -0
  65. package/docs/scripts/search.js +99 -0
  66. package/docs/styles/jsdoc.css +776 -0
  67. package/docs/styles/prettify.css +80 -0
  68. package/docs/toDatetimeUTC8.mjs.html +143 -0
  69. package/docs/toRocDate.mjs.html +107 -0
  70. package/g.mjs +73 -0
  71. package/package.json +31 -0
  72. package/script.txt +17 -0
  73. package/src/WDwdataHub.mjs +64 -0
  74. package/src/decodeEntities.mjs +57 -0
  75. package/src/extractDivContent.mjs +75 -0
  76. package/src/fetchAiNewsAggregator.mjs +83 -0
  77. package/src/fetchAisixiang.mjs +966 -0
  78. package/src/fetchCnyes.mjs +188 -0
  79. package/src/fetchGuancha.mjs +935 -0
  80. package/src/fetchHackerNews.mjs +117 -0
  81. package/src/fetchMoneydj.mjs +179 -0
  82. package/src/fetchMops.mjs +313 -0
  83. package/src/fetchRSS.mjs +88 -0
  84. package/src/fetchStatementdog.mjs +141 -0
  85. package/src/fetchTaifex.mjs +441 -0
  86. package/src/fetchTpex3insti.mjs +206 -0
  87. package/src/fetchTpexMargin.mjs +176 -0
  88. package/src/fetchTpexStock.mjs +127 -0
  89. package/src/fetchTwDataHoliday.mjs +164 -0
  90. package/src/fetchTwseMargin.mjs +181 -0
  91. package/src/fetchTwseStock.mjs +116 -0
  92. package/src/fetchTwseT86.mjs +136 -0
  93. package/src/fetchWithRetry.mjs +304 -0
  94. package/src/getOptFetch.mjs +113 -0
  95. package/src/htmlToMarkdown.mjs +96 -0
  96. package/src/isYmd.mjs +42 -0
  97. package/src/parseIntComma.mjs +28 -0
  98. package/src/safeFilename.mjs +30 -0
  99. package/src/toDatetimeUTC8.mjs +71 -0
  100. package/src/toRocDate.mjs +35 -0
  101. package/test/WDwdataHub.test.mjs +63 -0
  102. package/test/decodeEntities.test.mjs +42 -0
  103. package/test/extractDivContent.test.mjs +48 -0
  104. package/test/fetchAiNewsAggregator.test.mjs +79 -0
  105. package/test/fetchAisixiang.test.mjs +225 -0
  106. package/test/fetchCnyes.test.mjs +61 -0
  107. package/test/fetchGuancha.test.mjs +190 -0
  108. package/test/fetchHackerNews.test.mjs +78 -0
  109. package/test/fetchMoneydj.test.mjs +82 -0
  110. package/test/fetchMops.test.mjs +106 -0
  111. package/test/fetchRSS.test.mjs +85 -0
  112. package/test/fetchStatementdog.test.mjs +69 -0
  113. package/test/fetchTaifex.test.mjs +99 -0
  114. package/test/fetchTpex3insti.test.mjs +90 -0
  115. package/test/fetchTpexMargin.test.mjs +94 -0
  116. package/test/fetchTpexStock.test.mjs +68 -0
  117. package/test/fetchTwDataHoliday.test.mjs +100 -0
  118. package/test/fetchTwseMargin.test.mjs +81 -0
  119. package/test/fetchTwseStock.test.mjs +80 -0
  120. package/test/fetchTwseT86.test.mjs +76 -0
  121. package/test/fetchWithRetry.test.mjs +174 -0
  122. package/test/htmlToMarkdown.test.mjs +71 -0
  123. package/test/isYmd.test.mjs +56 -0
  124. package/test/parseIntComma.test.mjs +38 -0
  125. package/test/safeFilename.test.mjs +35 -0
  126. package/test/toDatetimeUTC8.test.mjs +65 -0
  127. package/test/toRocDate.test.mjs +38 -0
  128. package/test/tools/encodeBig5.mjs +80 -0
  129. package/test/tools/fixtures.mjs +539 -0
  130. package/test/tools/hasChrome.mjs +39 -0
  131. package/test/tools/serverForTest.mjs +397 -0
  132. package/toolg/addVersion.mjs +4 -0
  133. package/toolg/cleanFolder.mjs +5 -0
  134. package/toolg/gDistRollup.mjs +49 -0
  135. package/toolg/modifyReadme.mjs +4 -0
@@ -0,0 +1,80 @@
1
+ .pln {
2
+ color: #ddd;
3
+ }
4
+
5
+ /* string content */
6
+ .str {
7
+ color: #61ce3c;
8
+ }
9
+
10
+ /* a keyword */
11
+ .kwd {
12
+ color: #fbde2d;
13
+ }
14
+
15
+ /* a comment */
16
+ .com {
17
+ color: #aeaeae;
18
+ }
19
+
20
+ /* a type name */
21
+ .typ {
22
+ color: #8da6ce;
23
+ }
24
+
25
+ /* a literal value */
26
+ .lit {
27
+ color: #fbde2d;
28
+ }
29
+
30
+ /* punctuation */
31
+ .pun {
32
+ color: #ddd;
33
+ }
34
+
35
+ /* lisp open bracket */
36
+ .opn {
37
+ color: #000000;
38
+ }
39
+
40
+ /* lisp close bracket */
41
+ .clo {
42
+ color: #000000;
43
+ }
44
+
45
+ /* a markup tag name */
46
+ .tag {
47
+ color: #8da6ce;
48
+ }
49
+
50
+ /* a markup attribute name */
51
+ .atn {
52
+ color: #fbde2d;
53
+ }
54
+
55
+ /* a markup attribute value */
56
+ .atv {
57
+ color: #ddd;
58
+ }
59
+
60
+ /* a declaration */
61
+ .dec {
62
+ color: #EF5050;
63
+ }
64
+
65
+ /* a variable name */
66
+ .var {
67
+ color: #c82829;
68
+ }
69
+
70
+ /* a function name */
71
+ .fun {
72
+ color: #4271ae;
73
+ }
74
+
75
+ /* Specify class=linenums on a pre to get line numbering */
76
+ ol.linenums {
77
+ margin-top: 0;
78
+ margin-bottom: 0;
79
+ padding-bottom: 2px;
80
+ }
@@ -0,0 +1,143 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>toDatetimeUTC8.mjs - Documentation</title>
7
+
8
+
9
+ <script src="scripts/prettify/prettify.js"></script>
10
+ <script src="scripts/prettify/lang-css.js"></script>
11
+ <!--[if lt IE 9]>
12
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
13
+ <![endif]-->
14
+ <link type="text/css" rel="stylesheet" href="styles/prettify.css">
15
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
16
+ <script src="scripts/nav.js" defer></script>
17
+
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
19
+ </head>
20
+ <body>
21
+
22
+ <input type="checkbox" id="nav-trigger" class="nav-trigger" />
23
+ <label for="nav-trigger" class="navicon-button x">
24
+ <div class="navicon"></div>
25
+ </label>
26
+
27
+ <label for="nav-trigger" class="overlay"></label>
28
+
29
+ <nav >
30
+
31
+
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#KNOWN_TOPICS">KNOWN_TOPICS</a></li><li><a href="global.html#WDwdataHub">WDwdataHub</a></li><li><a href="global.html#assertTpexFieldShape">assertTpexFieldShape</a></li><li><a href="global.html#decodeEntities">decodeEntities</a></li><li><a href="global.html#extractAuthorFromContent">extractAuthorFromContent</a></li><li><a href="global.html#extractDivContent">extractDivContent</a></li><li><a href="global.html#extractHtmlTitle">extractHtmlTitle</a></li><li><a href="global.html#extractPubTime">extractPubTime</a></li><li><a href="global.html#extractTitle">extractTitle</a></li><li><a href="global.html#fetchAiNewsAggregator">fetchAiNewsAggregator</a></li><li><a href="global.html#fetchAisixiang">fetchAisixiang</a></li><li><a href="global.html#fetchAllListPages">fetchAllListPages</a></li><li><a href="global.html#fetchAllSearchPages">fetchAllSearchPages</a></li><li><a href="global.html#fetchArticle">fetchArticle</a></li><li><a href="global.html#fetchAuthorArticles">fetchAuthorArticles</a></li><li><a href="global.html#fetchAuthorsList">fetchAuthorsList</a></li><li><a href="global.html#fetchCnyes">fetchCnyes</a></li><li><a href="global.html#fetchFuturesData">fetchFuturesData</a></li><li><a href="global.html#fetchGuancha">fetchGuancha</a></li><li><a href="global.html#fetchHackerNews">fetchHackerNews</a></li><li><a href="global.html#fetchHtml">fetchHtml</a></li><li><a href="global.html#fetchInstitutionalData">fetchInstitutionalData</a></li><li><a href="global.html#fetchKeywordArticles">fetchKeywordArticles</a></li><li><a href="global.html#fetchMoneydj">fetchMoneydj</a></li><li><a href="global.html#fetchMops">fetchMops</a></li><li><a href="global.html#fetchOnce">fetchOnce</a></li><li><a href="global.html#fetchPCRatio">fetchPCRatio</a></li><li><a href="global.html#fetchRSS">fetchRSS</a></li><li><a href="global.html#fetchStatementdog">fetchStatementdog</a></li><li><a href="global.html#fetchTaifex">fetchTaifex</a></li><li><a href="global.html#fetchTargetWithRetry">fetchTargetWithRetry</a></li><li><a href="global.html#fetchTitleArticles">fetchTitleArticles</a></li><li><a href="global.html#fetchTopicArticles">fetchTopicArticles</a></li><li><a href="global.html#fetchTopicsList">fetchTopicsList</a></li><li><a href="global.html#fetchTpex3insti">fetchTpex3insti</a></li><li><a href="global.html#fetchTpexMargin">fetchTpexMargin</a></li><li><a href="global.html#fetchTpexStock">fetchTpexStock</a></li><li><a href="global.html#fetchTwDataHoliday">fetchTwDataHoliday</a></li><li><a href="global.html#fetchTwseMargin">fetchTwseMargin</a></li><li><a href="global.html#fetchTwseStock">fetchTwseStock</a></li><li><a href="global.html#fetchTwseT86">fetchTwseT86</a></li><li><a href="global.html#fetchWithRetry">fetchWithRetry</a></li><li><a href="global.html#getCfg">getCfg</a></li><li><a href="global.html#getOptFetch">getOptFetch</a></li><li><a href="global.html#getPayload">getPayload</a></li><li><a href="global.html#htmlToMarkdown">htmlToMarkdown</a></li><li><a href="global.html#isHomepageHtml">isHomepageHtml</a></li><li><a href="global.html#isNonHolidayEntry">isNonHolidayEntry</a></li><li><a href="global.html#isRetryableError">isRetryableError</a></li><li><a href="global.html#isYmd">isYmd</a></li><li><a href="global.html#lookupAuthor">lookupAuthor</a></li><li><a href="global.html#lookupTopic">lookupTopic</a></li><li><a href="global.html#parseAuthorColumnPage">parseAuthorColumnPage</a></li><li><a href="global.html#parseAuthorIndex">parseAuthorIndex</a></li><li><a href="global.html#parseCSV">parseCSV</a></li><li><a href="global.html#parseCSVLine">parseCSVLine</a></li><li><a href="global.html#parseIntComma">parseIntComma</a></li><li><a href="global.html#parseListPage">parseListPage</a></li><li><a href="global.html#parseNum">parseNum</a></li><li><a href="global.html#parseSearchResults">parseSearchResults</a></li><li><a href="global.html#parseSearchTotalPages">parseSearchTotalPages</a></li><li><a href="global.html#parseZhuantiArticles">parseZhuantiArticles</a></li><li><a href="global.html#pickPint">pickPint</a></li><li><a href="global.html#rocToWestern">rocToWestern</a></li><li><a href="global.html#safeFilename">safeFilename</a></li><li><a href="global.html#toDatetimeUTC8">toDatetimeUTC8</a></li><li><a href="global.html#toRocDate">toRocDate</a></li></ul>
33
+
34
+ </nav>
35
+
36
+ <div id="main">
37
+
38
+ <h1 class="page-title">toDatetimeUTC8.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>import ot from 'dayjs'
49
+ import utc from 'dayjs/plugin/utc.js'
50
+ import isnum from 'wsemi/src/isnum.mjs'
51
+ import isestr from 'wsemi/src/isestr.mjs'
52
+
53
+
54
+ //utc外掛, dayjs核心之format()一律以執行環境時區輸出, 需掛utc外掛才能以utcOffset指定固定偏移
55
+ ot.extend(utc)
56
+
57
+
58
+ //台灣時區偏移小時數, 台灣自1980年起無日光節約時間, 故固定為UTC+8
59
+ let TZ_OFFSET_HOUR = 8
60
+
61
+
62
+ //輸出格式
63
+ let FORMAT = 'YYYY-MM-DD HH:mm:ss'
64
+
65
+
66
+ /**
67
+ * 時間轉UTC+8之日期時間字串
68
+ *
69
+ * 可接受ISO時間字串、RFC822時間字串、unix秒數(非毫秒)或Date物件, 一律輸出台灣時間'YYYY-MM-DD HH:mm:ss';
70
+ * 以dayjs之utc外掛指定固定偏移+8, 不受執行環境時區影響(在UTC伺服器上結果相同)
71
+ *
72
+ * @param {String|Number|Date} value 輸入ISO或RFC822時間字串、unix秒數或Date物件
73
+ * @returns {String} 回傳UTC+8之日期時間字串,格式為'YYYY-MM-DD HH:mm:ss',輸入為空或無法解析時回傳''
74
+ * @example
75
+ *
76
+ * import toDatetimeUTC8 from './src/toDatetimeUTC8.mjs'
77
+ *
78
+ * console.log(toDatetimeUTC8('2026-08-07T01:02:03Z'))
79
+ * // => '2026-08-07 09:02:03'
80
+ *
81
+ * console.log(toDatetimeUTC8(1786000000))
82
+ * // => '2026-08-06 15:06:40'
83
+ *
84
+ * console.log(toDatetimeUTC8('abc'), toDatetimeUTC8(''), toDatetimeUTC8(null))
85
+ * // => '' '' ''
86
+ *
87
+ */
88
+ function toDatetimeUTC8(value) {
89
+
90
+ let dt = null
91
+
92
+ //數值一律視為unix秒數, dayjs之ot(number)為毫秒故須改用ot.unix
93
+ if (isnum(value)) {
94
+ if (value === 0) {
95
+ return ''
96
+ }
97
+ dt = ot.unix(value)
98
+ }
99
+ else if (value instanceof Date) {
100
+ dt = ot(value)
101
+ }
102
+ else if (isestr(value)) {
103
+ dt = ot(value)
104
+ }
105
+ else {
106
+ return ''
107
+ }
108
+
109
+ //check
110
+ if (!dt.isValid()) {
111
+ return ''
112
+ }
113
+
114
+ return dt.utcOffset(TZ_OFFSET_HOUR).format(FORMAT)
115
+ }
116
+
117
+
118
+ export default toDatetimeUTC8
119
+ </code></pre>
120
+ </article>
121
+ </section>
122
+
123
+
124
+
125
+
126
+
127
+
128
+ </div>
129
+
130
+ <br class="clear">
131
+
132
+ <footer>
133
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Aug 07 2026 12:04:51 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
134
+ </footer>
135
+
136
+ <script>prettyPrint();</script>
137
+ <script src="scripts/polyfill.js"></script>
138
+ <script src="scripts/linenumber.js"></script>
139
+
140
+
141
+
142
+ </body>
143
+ </html>
@@ -0,0 +1,107 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>toRocDate.mjs - Documentation</title>
7
+
8
+
9
+ <script src="scripts/prettify/prettify.js"></script>
10
+ <script src="scripts/prettify/lang-css.js"></script>
11
+ <!--[if lt IE 9]>
12
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
13
+ <![endif]-->
14
+ <link type="text/css" rel="stylesheet" href="styles/prettify.css">
15
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
16
+ <script src="scripts/nav.js" defer></script>
17
+
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
19
+ </head>
20
+ <body>
21
+
22
+ <input type="checkbox" id="nav-trigger" class="nav-trigger" />
23
+ <label for="nav-trigger" class="navicon-button x">
24
+ <div class="navicon"></div>
25
+ </label>
26
+
27
+ <label for="nav-trigger" class="overlay"></label>
28
+
29
+ <nav >
30
+
31
+
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#KNOWN_TOPICS">KNOWN_TOPICS</a></li><li><a href="global.html#WDwdataHub">WDwdataHub</a></li><li><a href="global.html#assertTpexFieldShape">assertTpexFieldShape</a></li><li><a href="global.html#decodeEntities">decodeEntities</a></li><li><a href="global.html#extractAuthorFromContent">extractAuthorFromContent</a></li><li><a href="global.html#extractDivContent">extractDivContent</a></li><li><a href="global.html#extractHtmlTitle">extractHtmlTitle</a></li><li><a href="global.html#extractPubTime">extractPubTime</a></li><li><a href="global.html#extractTitle">extractTitle</a></li><li><a href="global.html#fetchAiNewsAggregator">fetchAiNewsAggregator</a></li><li><a href="global.html#fetchAisixiang">fetchAisixiang</a></li><li><a href="global.html#fetchAllListPages">fetchAllListPages</a></li><li><a href="global.html#fetchAllSearchPages">fetchAllSearchPages</a></li><li><a href="global.html#fetchArticle">fetchArticle</a></li><li><a href="global.html#fetchAuthorArticles">fetchAuthorArticles</a></li><li><a href="global.html#fetchAuthorsList">fetchAuthorsList</a></li><li><a href="global.html#fetchCnyes">fetchCnyes</a></li><li><a href="global.html#fetchFuturesData">fetchFuturesData</a></li><li><a href="global.html#fetchGuancha">fetchGuancha</a></li><li><a href="global.html#fetchHackerNews">fetchHackerNews</a></li><li><a href="global.html#fetchHtml">fetchHtml</a></li><li><a href="global.html#fetchInstitutionalData">fetchInstitutionalData</a></li><li><a href="global.html#fetchKeywordArticles">fetchKeywordArticles</a></li><li><a href="global.html#fetchMoneydj">fetchMoneydj</a></li><li><a href="global.html#fetchMops">fetchMops</a></li><li><a href="global.html#fetchOnce">fetchOnce</a></li><li><a href="global.html#fetchPCRatio">fetchPCRatio</a></li><li><a href="global.html#fetchRSS">fetchRSS</a></li><li><a href="global.html#fetchStatementdog">fetchStatementdog</a></li><li><a href="global.html#fetchTaifex">fetchTaifex</a></li><li><a href="global.html#fetchTargetWithRetry">fetchTargetWithRetry</a></li><li><a href="global.html#fetchTitleArticles">fetchTitleArticles</a></li><li><a href="global.html#fetchTopicArticles">fetchTopicArticles</a></li><li><a href="global.html#fetchTopicsList">fetchTopicsList</a></li><li><a href="global.html#fetchTpex3insti">fetchTpex3insti</a></li><li><a href="global.html#fetchTpexMargin">fetchTpexMargin</a></li><li><a href="global.html#fetchTpexStock">fetchTpexStock</a></li><li><a href="global.html#fetchTwDataHoliday">fetchTwDataHoliday</a></li><li><a href="global.html#fetchTwseMargin">fetchTwseMargin</a></li><li><a href="global.html#fetchTwseStock">fetchTwseStock</a></li><li><a href="global.html#fetchTwseT86">fetchTwseT86</a></li><li><a href="global.html#fetchWithRetry">fetchWithRetry</a></li><li><a href="global.html#getCfg">getCfg</a></li><li><a href="global.html#getOptFetch">getOptFetch</a></li><li><a href="global.html#getPayload">getPayload</a></li><li><a href="global.html#htmlToMarkdown">htmlToMarkdown</a></li><li><a href="global.html#isHomepageHtml">isHomepageHtml</a></li><li><a href="global.html#isNonHolidayEntry">isNonHolidayEntry</a></li><li><a href="global.html#isRetryableError">isRetryableError</a></li><li><a href="global.html#isYmd">isYmd</a></li><li><a href="global.html#lookupAuthor">lookupAuthor</a></li><li><a href="global.html#lookupTopic">lookupTopic</a></li><li><a href="global.html#parseAuthorColumnPage">parseAuthorColumnPage</a></li><li><a href="global.html#parseAuthorIndex">parseAuthorIndex</a></li><li><a href="global.html#parseCSV">parseCSV</a></li><li><a href="global.html#parseCSVLine">parseCSVLine</a></li><li><a href="global.html#parseIntComma">parseIntComma</a></li><li><a href="global.html#parseListPage">parseListPage</a></li><li><a href="global.html#parseNum">parseNum</a></li><li><a href="global.html#parseSearchResults">parseSearchResults</a></li><li><a href="global.html#parseSearchTotalPages">parseSearchTotalPages</a></li><li><a href="global.html#parseZhuantiArticles">parseZhuantiArticles</a></li><li><a href="global.html#pickPint">pickPint</a></li><li><a href="global.html#rocToWestern">rocToWestern</a></li><li><a href="global.html#safeFilename">safeFilename</a></li><li><a href="global.html#toDatetimeUTC8">toDatetimeUTC8</a></li><li><a href="global.html#toRocDate">toRocDate</a></li></ul>
33
+
34
+ </nav>
35
+
36
+ <div id="main">
37
+
38
+ <h1 class="page-title">toRocDate.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>import isestr from 'wsemi/src/isestr.mjs'
49
+
50
+
51
+ /**
52
+ * 西元YYYYMMDD日期字串轉民國日期字串
53
+ *
54
+ * 民國年為西元年減1911, 月與日保留原始2碼不補零亦不去零, 以符合證交所與櫃買中心API之查詢格式
55
+ *
56
+ * @param {String} dateStr 輸入西元日期YYYYMMDD字串
57
+ * @returns {String} 回傳民國日期字串,格式為'YYY/MM/DD',輸入非有效字串時回傳''
58
+ * @example
59
+ *
60
+ * import toRocDate from './src/toRocDate.mjs'
61
+ *
62
+ * console.log(toRocDate('20260807'), toRocDate('19110101'))
63
+ * // => '115/08/07' '0/01/01'
64
+ *
65
+ */
66
+ function toRocDate(dateStr) {
67
+
68
+ //check
69
+ if (!isestr(dateStr)) {
70
+ return ''
71
+ }
72
+
73
+ //y, m, d
74
+ let y = parseInt(dateStr.substring(0, 4), 10) - 1911
75
+ let m = dateStr.substring(4, 6)
76
+ let d = dateStr.substring(6, 8)
77
+
78
+ return `${y}/${m}/${d}`
79
+ }
80
+
81
+
82
+ export default toRocDate
83
+ </code></pre>
84
+ </article>
85
+ </section>
86
+
87
+
88
+
89
+
90
+
91
+
92
+ </div>
93
+
94
+ <br class="clear">
95
+
96
+ <footer>
97
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Aug 07 2026 12:04:51 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
98
+ </footer>
99
+
100
+ <script>prettyPrint();</script>
101
+ <script src="scripts/polyfill.js"></script>
102
+ <script src="scripts/linenumber.js"></script>
103
+
104
+
105
+
106
+ </body>
107
+ </html>
package/g.mjs ADDED
@@ -0,0 +1,73 @@
1
+ import wi from './src/WDwdataHub.mjs'
2
+
3
+
4
+ let test = async () => {
5
+
6
+ //綜合新聞: RSS訂閱源, 回傳統一格式{url,time,title,description,from}
7
+ let r1 = await wi.fetchRSS('https://www.ptt.cc/atom/Gossiping.xml', { showLog: false })
8
+ console.log('rss:', r1.length, r1[0].time, r1[0].title)
9
+ // => rss: 19 2026-08-07 09:30:19 [問卦] 公視是怎麼走到今天這一步的?
10
+
11
+ //綜合新聞: Hacker News最新文章, 可指定取回篇數
12
+ let r2 = await wi.fetchHackerNews(5, { showLog: false })
13
+ console.log('hackerNews:', r2.length, r2[0].from, r2[0].title)
14
+ // => hackerNews: 5 Hacker News Romania blasts rock to divert water from drought-hit Danube to nuclear reactor
15
+
16
+ //綜合新聞: AI News Aggregator近24小時彙整
17
+ let r3 = await wi.fetchAiNewsAggregator({ showLog: false })
18
+ console.log('aiNews:', r3.length, r3[0].from)
19
+ // => aiNews: 914 夕小瑶科技说
20
+
21
+ //台股新聞: 鉅亨網, 逐頁抓至targetTotal則
22
+ let r4 = await wi.fetchCnyes({ targetTotal: 30, showLog: false })
23
+ console.log('cnyes:', r4.length, r4[0].time, r4[0].link)
24
+ // => cnyes: 30 2026-08-07 09:20:46 https://news.cnyes.com/news/id/6563766
25
+
26
+ //台股資料: 證交所上市個股日成交資訊, 指定日期會由整月資料過濾為當日單筆
27
+ let r5 = await wi.fetchTwseStock('20260806', '2330', { showLog: false })
28
+ console.log('twseStock:', r5.stat, r5.data.length, r5.data[0][6])
29
+ // => twseStock: OK 1 2,365.00
30
+
31
+ //台股資料: 櫃買中心上櫃融資融券, 未指定個股則回全市場
32
+ let r6 = await wi.fetchTpexMargin('20260806', ['6488'], { showLog: false })
33
+ console.log('tpexMargin:', r6.source, r6.count, r6.data[0].marginChange)
34
+ // => tpexMargin: tpex_margin 1 -694
35
+
36
+ //台股資料: 期交所台指期、三大法人未平倉與Put/Call Ratio, 單支失敗僅記於errors
37
+ let r7 = await wi.fetchTaifex('20260806', { showLog: false })
38
+ console.log('taifex:', r7.futures.tx.close, r7.pcRatio.ratio, r7.errors)
39
+ // => taifex: 44280 109.14 []
40
+
41
+ //台股資料: 證交所休市日期, 給定日期則另回傳該日是否休市
42
+ let r8 = await wi.fetchTwDataHoliday('20260101', { showLog: false })
43
+ console.log('holiday:', r8.dataYear, r8.totalHolidays, r8.isHoliday, r8.holidayName)
44
+ // => holiday: 2026 22 true 中華民國開國紀念日
45
+
46
+ //中文評論網站: 愛思想, 依作者中文名查專欄文章清單
47
+ let r9 = await wi.fetchAisixiang.fetchAuthorArticles({ name: '葛兆光', showLog: false })
48
+ console.log('aisixiang:', r9.status, r9.resolved.slug, r9.count)
49
+ // => aisixiang: success gezhaoguang 170
50
+
51
+ //中文評論網站: 愛思想, 抓單篇文章轉為含frontmatter之Markdown
52
+ let r10 = await wi.fetchAisixiang.fetchArticle({ aid: '146669', showLog: false })
53
+ console.log('aisixiang:', r10.status, r10.title, r10.chars)
54
+ // => aisixiang: success 葛兆光:禅宗与中国文化 16986
55
+
56
+ //中文評論網站: 觀察者網, 依主題中文名查文章清單, 自動選用可翻頁之欄目slug
57
+ let r11 = await wi.fetchGuancha.fetchTopicArticles({ name: '财经', maxPages: 1, showLog: false })
58
+ console.log('guancha:', r11.status, r11.resolved.slug, r11.count)
59
+ // => guancha: success CaiJing 30
60
+
61
+ //查無資料時回status為success且count為0, 抓取失敗才回status為error, 兩者可明確區分
62
+ let r12 = await wi.fetchGuancha.fetchAuthorArticles({ name: '不存在的作者XYZ', showLog: false })
63
+ console.log('guancha:', r12.status, r12.count, r12.message)
64
+ // => guancha: success 0 "不存在的作者XYZ" 不在觀察者網作者索引中(共 641 位)。尚無此作者文章。提醒:本函數不轉繁簡,呼叫端負責用站方登錄字形(簡體)。
65
+
66
+ }
67
+ await test()
68
+ .catch((err) => {
69
+ console.log(err)
70
+ })
71
+
72
+
73
+ //node g.mjs
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "w-dwdata-hub",
3
+ "version": "1.0.0",
4
+ "main": "dist/w-dwdata-hub.umd.js",
5
+ "dependencies": {
6
+ "cheerio": "^1.2.0",
7
+ "lodash-es": "^4.18.1",
8
+ "rss-parser": "^3.13.0",
9
+ "w-fetch-web": "^1.0.1",
10
+ "wsemi": "^1.8.67"
11
+ },
12
+ "devDependencies": {
13
+ "w-package-tools": "^1.1.12"
14
+ },
15
+ "scripts": {
16
+ "test": "mocha --parallel --timeout 180000",
17
+ "deploy": "gh-pages -d docs"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/yuda-lyu/w-dwdata-hub.git"
22
+ },
23
+ "keywords": [
24
+ "package",
25
+ "tool",
26
+ "download",
27
+ "nodejs"
28
+ ],
29
+ "author": "yuda-lyu(semisphere)",
30
+ "license": "MIT"
31
+ }
package/script.txt ADDED
@@ -0,0 +1,17 @@
1
+ #node toolg/addVersion.mjs
2
+ node toolg/modifyReadme.mjs
3
+
4
+ node toolg/cleanFolder.mjs
5
+ ./node_modules/.bin/jsdoc -c .jsdoc
6
+
7
+ node toolg/gDistRollup.mjs
8
+
9
+ git add . -A
10
+ git commit -m 'modify: '
11
+ git push origin master:master
12
+
13
+ npm run deploy
14
+
15
+ #npm test
16
+
17
+ #npm publish
@@ -0,0 +1,64 @@
1
+ import fetchAiNewsAggregator from './fetchAiNewsAggregator.mjs'
2
+ import fetchAisixiang from './fetchAisixiang.mjs'
3
+ import fetchCnyes from './fetchCnyes.mjs'
4
+ import fetchGuancha from './fetchGuancha.mjs'
5
+ import fetchHackerNews from './fetchHackerNews.mjs'
6
+ import fetchMoneydj from './fetchMoneydj.mjs'
7
+ import fetchMops from './fetchMops.mjs'
8
+ import fetchRSS from './fetchRSS.mjs'
9
+ import fetchStatementdog from './fetchStatementdog.mjs'
10
+ import fetchTaifex from './fetchTaifex.mjs'
11
+ import fetchTpex3insti from './fetchTpex3insti.mjs'
12
+ import fetchTpexMargin from './fetchTpexMargin.mjs'
13
+ import fetchTpexStock from './fetchTpexStock.mjs'
14
+ import fetchTwDataHoliday from './fetchTwDataHoliday.mjs'
15
+ import fetchTwseMargin from './fetchTwseMargin.mjs'
16
+ import fetchTwseStock from './fetchTwseStock.mjs'
17
+ import fetchTwseT86 from './fetchTwseT86.mjs'
18
+
19
+
20
+ /**
21
+ * 資料下載中心
22
+ *
23
+ * 各函數依資料來源分為三類:
24
+ * 綜合新聞(fetchRSS、fetchHackerNews、fetchAiNewsAggregator);
25
+ * 台股新聞與資料(fetchCnyes、fetchMoneydj、fetchStatementdog、fetchMops、fetchTwseStock、fetchTpexStock、fetchTwseMargin、fetchTpexMargin、fetchTwseT86、fetchTpex3insti、fetchTaifex、fetchTwDataHoliday);
26
+ * 中文評論網站(fetchAisixiang、fetchGuancha),此二者為物件,其內再含多個抓取函數
27
+ *
28
+ * @returns {Object} 回傳物件,其內可呼叫fetchRSS、fetchHackerNews、fetchAiNewsAggregator、fetchCnyes、fetchMoneydj、fetchStatementdog、fetchMops、fetchTwseStock、fetchTpexStock、fetchTwseMargin、fetchTpexMargin、fetchTwseT86、fetchTpex3insti、fetchTaifex、fetchTwDataHoliday之async函數,及fetchAisixiang、fetchGuancha之物件
29
+ * @example
30
+ *
31
+ * 詳見各fetch函數範例
32
+ *
33
+ */
34
+ let WDwdataHub = {
35
+
36
+ //綜合新聞
37
+ fetchRSS,
38
+ fetchHackerNews,
39
+ fetchAiNewsAggregator,
40
+
41
+ //台股新聞
42
+ fetchCnyes,
43
+ fetchMoneydj,
44
+ fetchStatementdog,
45
+ fetchMops,
46
+
47
+ //台股資料
48
+ fetchTwseStock,
49
+ fetchTpexStock,
50
+ fetchTwseMargin,
51
+ fetchTpexMargin,
52
+ fetchTwseT86,
53
+ fetchTpex3insti,
54
+ fetchTaifex,
55
+ fetchTwDataHoliday,
56
+
57
+ //中文評論網站
58
+ fetchAisixiang,
59
+ fetchGuancha,
60
+
61
+ }
62
+
63
+
64
+ export default WDwdataHub
@@ -0,0 +1,57 @@
1
+ import isstr from 'wsemi/src/isstr.mjs'
2
+
3
+
4
+ //常用具名HTML實體對照表, 涵蓋中文網站正文常見者
5
+ let NAMED = {
6
+ nbsp: ' ',
7
+ amp: '&',
8
+ lt: '<',
9
+ gt: '>',
10
+ quot: '"',
11
+ apos: '\'',
12
+ hellip: '…',
13
+ mdash: '—',
14
+ ndash: '–',
15
+ middot: '·',
16
+ ldquo: '"',
17
+ rdquo: '"',
18
+ lsquo: '‘',
19
+ rsquo: '’',
20
+ laquo: '«',
21
+ raquo: '»',
22
+ copy: '©',
23
+ reg: '®',
24
+ }
25
+
26
+
27
+ /**
28
+ * 解碼HTML實體
29
+ *
30
+ * 支援具名實體(如&amp;)、十進位數值實體(如&#39;)與十六進位數值實體(如&#x27;),
31
+ * 無對照之具名實體保留原字串不動
32
+ *
33
+ * @param {String} str 輸入含HTML實體之字串
34
+ * @returns {String} 回傳解碼後字串,輸入非字串時回傳''
35
+ * @example
36
+ *
37
+ * import decodeEntities from './src/decodeEntities.mjs'
38
+ *
39
+ * console.log(decodeEntities('a&amp;b&#65;&#x42;&unknown;'))
40
+ * // => 'a&bAB&unknown;'
41
+ *
42
+ */
43
+ function decodeEntities(str) {
44
+
45
+ //check
46
+ if (!isstr(str)) {
47
+ return ''
48
+ }
49
+
50
+ return str
51
+ .replace(/&([a-zA-Z]+);/g, (m, n) => (NAMED[n] !== undefined ? NAMED[n] : m))
52
+ .replace(/&#(\d+);/g, (m, n) => String.fromCodePoint(Number(n)))
53
+ .replace(/&#x([\da-fA-F]+);/g, (m, n) => String.fromCodePoint(parseInt(n, 16)))
54
+ }
55
+
56
+
57
+ export default decodeEntities
@@ -0,0 +1,75 @@
1
+ import isstr from 'wsemi/src/isstr.mjs'
2
+ import isestr from 'wsemi/src/isestr.mjs'
3
+
4
+
5
+ /**
6
+ * 由HTML切出指定class之div內容
7
+ *
8
+ * 以深度追蹤(depth tracking)配對div開閉標籤, 比僅取首個</div>可靠, 亦能正確切出0結果之空容器;
9
+ * 起始標籤採前綴比對, 故div上帶有其他屬性(如<div class="content all-txt" id="x">)亦可命中
10
+ *
11
+ * @param {String} html 輸入HTML字串
12
+ * @param {String} className 輸入div之class屬性字串
13
+ * @returns {String|null} 回傳div內容字串,找不到起始標籤或標籤未閉合時回傳null
14
+ * @example
15
+ *
16
+ * import extractDivContent from './src/extractDivContent.mjs'
17
+ *
18
+ * console.log(extractDivContent('<div class="ct">a<div>b</div>c</div>', 'ct'))
19
+ * // => 'a<div>b</div>c'
20
+ *
21
+ * console.log(extractDivContent('<div class="other">a</div>', 'ct'))
22
+ * // => null
23
+ *
24
+ */
25
+ function extractDivContent(html, className) {
26
+
27
+ //check
28
+ if (!isstr(html)) {
29
+ return null
30
+ }
31
+ if (!isestr(className)) {
32
+ return null
33
+ }
34
+
35
+ //startIdx, 前綴比對以容忍div帶有其他屬性
36
+ let startTag = `<div class="${className}"`
37
+ let startIdx = html.indexOf(startTag)
38
+ if (startIdx === -1) {
39
+ return null
40
+ }
41
+
42
+ //tagClose, 找起始標籤之'>'
43
+ let tagClose = html.indexOf('>', startIdx)
44
+ if (tagClose === -1) {
45
+ return null
46
+ }
47
+
48
+ //depth, 逐一配對div開閉標籤
49
+ let contentStart = tagClose + 1
50
+ let i = contentStart
51
+ let depth = 1
52
+ while (depth > 0 && i < html.length) {
53
+ let open = html.indexOf('<div', i)
54
+ let close = html.indexOf('</div>', i)
55
+ if (close === -1) {
56
+ return null
57
+ }
58
+ if (open !== -1 && open < close) {
59
+ depth++
60
+ i = open + 4
61
+ }
62
+ else {
63
+ depth--
64
+ if (depth === 0) {
65
+ return html.slice(contentStart, close)
66
+ }
67
+ i = close + 6
68
+ }
69
+ }
70
+
71
+ return null
72
+ }
73
+
74
+
75
+ export default extractDivContent