Skip to content
This repository was archived by the owner on Mar 3, 2026. It is now read-only.

Commit 850733c

Browse files
authored
refactor(deps): Remove dependency date-and-time in favor of utility (#1928)
function refactor(deps): Remove date-and-time dependency in favor of utility function
1 parent 5d8bfd0 commit 850733c

6 files changed

Lines changed: 62 additions & 51 deletions

File tree

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
"async-retry": "^1.3.3",
6060
"compressible": "^2.0.12",
6161
"configstore": "^5.0.0",
62-
"date-and-time": "^2.0.0",
6362
"duplexify": "^4.0.0",
6463
"ent": "^2.2.0",
6564
"extend": "^3.0.2",

src/file.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import {promisifyAll} from '@google-cloud/promisify';
2525

2626
import compressible = require('compressible');
2727
import * as crypto from 'crypto';
28-
import * as dateFormat from 'date-and-time';
2928
import * as extend from 'extend';
3029
import * as fs from 'fs';
3130
// eslint-disable-next-line @typescript-eslint/no-var-requires
@@ -65,7 +64,12 @@ import {
6564
} from './nodejs-common/util';
6665
// eslint-disable-next-line @typescript-eslint/no-var-requires
6766
const duplexify: DuplexifyConstructor = require('duplexify');
68-
import {normalize, objectKeyToLowercase, unicodeJSONStringify} from './util';
67+
import {
68+
normalize,
69+
objectKeyToLowercase,
70+
unicodeJSONStringify,
71+
formatAsUTCISO,
72+
} from './util';
6973
import retry = require('async-retry');
7074

7175
export type GetExpirationDateResponse = [Date];
@@ -2760,8 +2764,8 @@ class File extends ServiceObject<File> {
27602764
let fields = Object.assign({}, options.fields);
27612765

27622766
const now = new Date();
2763-
const nowISO = dateFormat.format(now, 'YYYYMMDD[T]HHmmss[Z]', true);
2764-
const todayISO = dateFormat.format(now, 'YYYYMMDD', true);
2767+
const nowISO = formatAsUTCISO(now, true);
2768+
const todayISO = formatAsUTCISO(now);
27652769

27662770
const sign = async () => {
27672771
const {client_email} = await this.storage.authClient.getCredentials();
@@ -2786,11 +2790,7 @@ class File extends ServiceObject<File> {
27862790

27872791
delete fields.bucket;
27882792

2789-
const expiration = dateFormat.format(
2790-
expires,
2791-
'YYYY-MM-DD[T]HH:mm:ss[Z]',
2792-
true
2793-
);
2793+
const expiration = formatAsUTCISO(expires, true, '-', ':');
27942794

27952795
const policy = {
27962796
conditions,

src/signer.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@
1313
// limitations under the License.
1414

1515
import * as crypto from 'crypto';
16-
import * as dateFormat from 'date-and-time';
1716
import * as http from 'http';
1817
import * as url from 'url';
1918
import {ExceptionMessages} from './storage';
20-
import {encodeURI, qsStringify, objectEntries} from './util';
19+
import {encodeURI, qsStringify, objectEntries, formatAsUTCISO} from './util';
2120

2221
interface GetCredentialsResponse {
2322
client_email?: string;
@@ -268,15 +267,14 @@ export class URLSigner {
268267

269268
const extensionHeadersString = this.getCanonicalHeaders(extensionHeaders);
270269

271-
const datestamp = dateFormat.format(config.accessibleAt, 'YYYYMMDD', true);
270+
const datestamp = formatAsUTCISO(config.accessibleAt);
272271
const credentialScope = `${datestamp}/auto/storage/goog4_request`;
273272

274273
const sign = async () => {
275274
const credentials = await this.authClient.getCredentials();
276275
const credential = `${credentials.client_email}/${credentialScope}`;
277-
const dateISO = dateFormat.format(
276+
const dateISO = formatAsUTCISO(
278277
config.accessibleAt ? config.accessibleAt : new Date(),
279-
'YYYYMMDD[T]HHmmss[Z]',
280278
true
281279
);
282280
const queryParams: Query = {

src/util.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,38 @@ export function convertObjKeysToSnakeCase(obj: object): object {
131131

132132
return obj;
133133
}
134+
135+
/**
136+
* Formats the provided date object as a UTC ISO string.
137+
* @param {Date} dateTimeToFormat date object to be formatted.
138+
* @param {boolean} includeTime flag to include hours, minutes, seconds in output.
139+
* @param {string} dateDelimiter delimiter between date components.
140+
* @param {string} timeDelimiter delimiter between time components.
141+
* @returns {string} UTC ISO format of provided date obect.
142+
*/
143+
export function formatAsUTCISO(
144+
dateTimeToFormat: Date,
145+
includeTime = false,
146+
dateDelimiter = '',
147+
timeDelimiter = ''
148+
): string {
149+
const year = dateTimeToFormat.getUTCFullYear();
150+
const month = dateTimeToFormat.getUTCMonth() + 1;
151+
const day = dateTimeToFormat.getUTCDate();
152+
const hour = dateTimeToFormat.getUTCHours();
153+
const minute = dateTimeToFormat.getUTCMinutes();
154+
const second = dateTimeToFormat.getUTCSeconds();
155+
156+
let resultString = `${year.toString().padStart(4, '0')}${dateDelimiter}${month
157+
.toString()
158+
.padStart(2, '0')}${dateDelimiter}${day.toString().padStart(2, '0')}`;
159+
if (includeTime) {
160+
resultString = `${resultString}T${hour
161+
.toString()
162+
.padStart(2, '0')}${timeDelimiter}${minute
163+
.toString()
164+
.padStart(2, '0')}${timeDelimiter}${second.toString().padStart(2, '0')}Z`;
165+
}
166+
167+
return resultString;
168+
}

test/file.ts

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import {PromisifyAllOptions} from '@google-cloud/promisify';
2525
import {Readable, PassThrough, Stream, Duplex, Transform} from 'stream';
2626
import * as assert from 'assert';
2727
import * as crypto from 'crypto';
28-
import * as dateFormat from 'date-and-time';
2928
import * as duplexify from 'duplexify';
3029
import * as extend from 'extend';
3130
import * as fs from 'fs';
@@ -57,6 +56,7 @@ import {
5756
FileExceptionMessages,
5857
} from '../src/file';
5958
import {ExceptionMessages, IdempotencyStrategy} from '../src/storage';
59+
import {formatAsUTCISO} from '../src/util';
6060

6161
class HTTPError extends Error {
6262
code: number;
@@ -3324,11 +3324,7 @@ describe('File', () => {
33243324
{bucket: BUCKET.name},
33253325
...fieldsToConditions(requiredFields),
33263326
],
3327-
expiration: dateFormat.format(
3328-
new Date(CONFIG.expires),
3329-
'YYYY-MM-DD[T]HH:mm:ss[Z]',
3330-
true
3331-
),
3327+
expiration: formatAsUTCISO(new Date(CONFIG.expires), true, '-', ':'),
33323328
};
33333329

33343330
const policyString = JSON.stringify(policy);
@@ -3548,7 +3544,7 @@ describe('File', () => {
35483544
);
35493545
assert.strictEqual(
35503546
policy.expiration,
3551-
dateFormat.format(expires, 'YYYY-MM-DD[T]HH:mm:ss[Z]', true)
3547+
formatAsUTCISO(expires, true, '-', ':')
35523548
);
35533549
done();
35543550
}
@@ -3569,22 +3565,18 @@ describe('File', () => {
35693565
);
35703566
assert.strictEqual(
35713567
policy.expiration,
3572-
dateFormat.format(
3573-
new Date(expires),
3574-
'YYYY-MM-DD[T]HH:mm:ss[Z]',
3575-
true
3576-
)
3568+
formatAsUTCISO(new Date(expires), true, '-', ':')
35773569
);
35783570
done();
35793571
}
35803572
);
35813573
});
35823574

35833575
it('should accept strings', done => {
3584-
const expires = dateFormat.format(
3576+
const expires = formatAsUTCISO(
35853577
new Date(Date.now() + 2 * 24 * 60 * 60 * 1000),
3586-
'YYYY-MM-DD',
3587-
true
3578+
false,
3579+
'-'
35883580
);
35893581

35903582
file.generateSignedPostPolicyV4(
@@ -3598,11 +3590,7 @@ describe('File', () => {
35983590
);
35993591
assert.strictEqual(
36003592
policy.expiration,
3601-
dateFormat.format(
3602-
new Date(expires),
3603-
'YYYY-MM-DD[T]HH:mm:ss[Z]',
3604-
true
3605-
)
3593+
formatAsUTCISO(new Date(expires), true, '-', ':')
36063594
);
36073595
done();
36083596
}

test/signer.ts

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414
import * as assert from 'assert';
15-
import * as dateFormat from 'date-and-time';
1615
import * as crypto from 'crypto';
1716
import * as sinon from 'sinon';
1817
import {describe, it, beforeEach, afterEach} from 'mocha';
@@ -29,7 +28,7 @@ import {
2928
Query,
3029
SignerExceptionMessages,
3130
} from '../src/signer';
32-
import {encodeURI, qsStringify} from '../src/util';
31+
import {encodeURI, formatAsUTCISO, qsStringify} from '../src/util';
3332
import {ExceptionMessages} from '../src/storage';
3433

3534
describe('signer', () => {
@@ -187,11 +186,7 @@ describe('signer', () => {
187186
expires: expiresNumber,
188187
});
189188
const blobToSign = authClientSign.getCall(0).args[0];
190-
assert(
191-
blobToSign.includes(
192-
dateFormat.format(accessibleAt, 'YYYYMMDD[T]HHmmss[Z]', true)
193-
)
194-
);
189+
assert(blobToSign.includes(formatAsUTCISO(accessibleAt, true)));
195190
});
196191

197192
it('should throw if an expiration date from the before accessibleAt date is given', () => {
@@ -211,11 +206,7 @@ describe('signer', () => {
211206

212207
describe('checkInputTypes', () => {
213208
const query = {
214-
'X-Goog-Date': dateFormat.format(
215-
new Date(accessibleAtNumber),
216-
'YYYYMMDD[T]HHmmss[Z]',
217-
true
218-
),
209+
'X-Goog-Date': formatAsUTCISO(new Date(accessibleAtNumber), true),
219210
};
220211

221212
it('should accept Date objects', async () => {
@@ -688,7 +679,7 @@ describe('signer', () => {
688679
const query = (await signer['getSignedUrlV4'](CONFIG)) as Query;
689680
const arg = getCanonicalQueryParams.getCall(0).args[0];
690681

691-
const datestamp = dateFormat.format(NOW, 'YYYYMMDD', true);
682+
const datestamp = formatAsUTCISO(NOW);
692683
const credentialScope = `${datestamp}/auto/storage/goog4_request`;
693684
const EXPECTED_CREDENTIAL = `${CLIENT_EMAIL}/${credentialScope}`;
694685

@@ -697,7 +688,7 @@ describe('signer', () => {
697688
});
698689

699690
it('should populate X-Goog-Date', async () => {
700-
const dateISO = dateFormat.format(NOW, 'YYYYMMDD[T]HHmmss[Z]', true);
691+
const dateISO = formatAsUTCISO(NOW, true);
701692

702693
const query = (await signer['getSignedUrlV4'](CONFIG)) as Query;
703694
const arg = getCanonicalQueryParams.getCall(0).args[0];
@@ -787,9 +778,9 @@ describe('signer', () => {
787778
});
788779

789780
it('should compose blobToSign', async () => {
790-
const datestamp = dateFormat.format(NOW, 'YYYYMMDD', true);
781+
const datestamp = formatAsUTCISO(NOW);
791782
const credentialScope = `${datestamp}/auto/storage/goog4_request`;
792-
const dateISO = dateFormat.format(NOW, 'YYYYMMDD[T]HHmmss[Z]', true);
783+
const dateISO = formatAsUTCISO(NOW, true);
793784

794785
const authClientSign = sinon
795786
.stub(authClient, 'sign')

0 commit comments

Comments
 (0)