Tại sao không trả về ngày dưới dạng một chuỗi từ cơ sở dữ liệu?


41

Trong một ứng dụng web thông thường, ngày được lấy từ lớp cơ sở dữ liệu được gõ mạnh (ví dụ: trong c # là System.DateTime thay vì System.String).

Khi một ngày cần được thể hiện dưới dạng một chuỗi (ví dụ: được hiển thị trên một trang), việc chuyển đổi từ DateTime thành chuỗi được thực hiện trong lớp trình bày.

Tại sao lại thế này? Tại sao việc chuyển đổi DateTime thành một chuỗi trên tầng cơ sở dữ liệu là một điều xấu?

Xem thêm các cuộc tranh luận sôi nổi trong trò chuyện , và câu hỏi ban đầu đã bắt đầu tất cả những điều này .


73
Hãy để tôi hỏi bạn điều này: bạn có thể chuyển đổi từng loại thành một chuỗi không? Điều gì làm cho ngày khác nhau?
vườn

7
Câu hỏi hay! Xin vui lòng xem các cuộc tranh luận sôi nổi trong tiến trình, ở đây .
John Wu

8
Chà, có vẻ như khá rõ ràng rằng anh chàng kia đã sai, và mọi người khác đều đúng. Không thực sự là một câu hỏi ở đây
vườn

7
Đôi khi bạn cần làm toán ngày ngoài cơ sở dữ liệu. Khó hơn đáng kể nếu tất cả những gì bạn có là chuỗi.
Eric King

14
Một vấn đề khác - bạn cần loại chuỗi nào? Có rất nhiều cách để biểu diễn một datetime dưới dạng một chuỗi. Điều gì sẽ xảy ra nếu tôi có một cơ sở dữ liệu chỉ trả về thời gian hiện tại, được biểu thị bằng # giây kể từ thời đại, dưới dạng chuỗi (ví dụ: thời gian hiện tại là "1474496980"). Điều đó sẽ hữu ích? Bạn có muốn sử dụng một cơ sở dữ liệu như vậy?
riwalk

Câu trả lời:


168

Ngày, DateTimes và thực sự là bất kỳ đối tượng được nhập nào khác, thường nên được để ở định dạng được nhập đúng cho đến khi bạn cần chuyển chúng thành một loại khác - đặc biệt là khi loại đó là dạng dễ đọc của con người và đặc biệt là khi nó bị mất / loại chuyển đổi một chiều.

Tại sao? Bởi vì người ta cho rằng loại này cung cấp cho bạn rất nhiều chức năng được tích hợp sẵn, như kiểm tra đẳng thức, cộng và trừ, so sánh (lớn hơn, nhỏ hơn), chức năng múi giờ và miền địa phương (đặc biệt quan trọng đối với mọi thứ liên quan đến thời gian), v.v ... Nếu bạn quyết định muốn hỗ trợ người Mỹ và định dạng "Tháng ngày [năm], năm" cũng như phong cách phổ biến của Anh là "Ngày tháng năm", hoặc tiêu chuẩn ISO của "Năm tháng"? Bạn sẽ làm gì nếu đó là một chuỗi và bạn cần thực hiện thay đổi đó, phân tích lại thành Ngày? Ugh, không, cảm ơn - có rất nhiều tệ nạn và lỗi nghiêm trọng theo cách đó, tốt nhất nên tránh hoàn toàn.

Cụ thể hơn, bạn đã đề cập đến kiến ​​trúc theo tầng, có lớp trình bày tách biệt với dữ liệu sau này. Đây thực sự là một lý do lớn khác để vượt qua một Ngày là một Ngày chứ không phải là một chuỗi - bởi vì ngày nào nên đưa vào định dạng chuỗi? Tiếng Anh, tiếng Trung, có hoặc không có giây / mili giây, tên tháng hoặc chữ số đầy đủ, bạn sẽ muốn sắp xếp trên trường ngày sau (sắp xếp theo chuỗi yêu cầu một định dạng chuỗi nhất định nếu bạn muốn nó hoạt động đúng), v.v? Đây hoàn toàn là một câu hỏi về cách trình bày - người dùng nên xem dữ liệu như thế nào - và đặt logic đó ở bất kỳ nơi nào khác sẽ hạn chế lợi thế của việc có kiến ​​trúc theo tầng ở vị trí đầu tiên. Cơ sở dữ liệu không cần biết hoặc quan tâm bạn sẽ muốn xem ngày như thế nào trong tương lai.

Cuối cùng, gần như tất cả các ứng dụng phức tạp (vốn là kiến ​​trúc được xếp lớp), quan tâm đến thời gian chắc chắn sẽ sử dụng thời gian / ngày theo nhiều cách, nhiều cách khác nhau và thường ở mọi cấp độ khác nhau của kiến ​​trúc. Các đối tượng đánh máy liên quan đến thời gian và ngày tháng tồn tại vì một lý do thực sự tốt: bản thân thời gian và đặc biệt là hệ thống lịch của con người, thật kỳ lạ và khó. Cuối cùng, thời gian và ngày tháng không phải là chuỗi vì cùng một lý do là số nguyên và dấu phẩy động không phải là chuỗi và nó sẽ chỉ khiến cuộc sống của bạn trở nên khó khăn hơn nếu bạn cố gắng giả vờ rằng chúng thực sự chỉ là một mảng các ký tự, bởi vì chúng chỉ là không.


26
+1 chỉ để sử dụng từ này một cách nhanh chóng. Tôi đồng ý với các lập luận thuyết phục và giải thích toàn diện của bạn, nhưng đó là lý do tại sao tôi phải đăng nhập và bỏ phiếu cho bạn.
Adrian Larson

1
Đại diện cho thời gian là giây kể từ một thời điểm xác định trong quá khứ cũng mạnh mẽ giữa các lịch khác nhau. Ví dụ, lịch Hồi giáo và Trung Quốc không sử dụng bất kỳ tháng nào của Greogrian, số năm, v.v. Tôi sẽ coi việc xử lý việc này ở cấp cơ sở dữ liệu là thông lệ xấu.
rexkogitans

Ngày thường được trình bày là "X ngày trước". Chúc may mắn phân tích mà trở lại giá trị ban đầu.
Đặc vụ_L

5
Chúng ta cũng đừng quên các vấn đề thay đổi DST (và các vấn đề tương tự khác). Sẽ "ngày 06 Tháng 11 2016 01:30:26" là lần đầu tiên hay lần thứ hai ngày và giờ này sẽ xảy ra? UTC DateTime ít nhất là duy nhất và bạn luôn có thể dịch nó thành đại diện cục bộ cho lần đó - quay lại theo cách khác không phải lúc nào cũng có thể.
J ...

3
Why? Because it is assumed that the type provides you with lots of handy built in functionalityTheo tôi đây chỉ là thứ yếu. Lý do thực sự là loại cho bạn biết cái gì đó là gì . Một ngày không phải là một chuỗi, nó chỉ xảy ra để dịch dễ dàng thành một chuỗi có thể đọc được.
Doval

53

Ông đang nói sẽ sử dụng máy chủ web để chuyển đổi thời gian dữ liệu thành một chuỗi. Tôi đang nói làm điều đó trên máy chủ cơ sở dữ liệu chứ không phải máy chủ web. Tại sao bạn nghĩ rằng tốt hơn? - Đầu MT

Tôi muốn biết loại.

Tôi thực sự không quan tâm nếu cơ sở dữ liệu của bạn lưu trữ thông tin trong một chuỗi, một số int hoặc byte, bởi vì, cuối cùng thì nó luôn luôn là byte. Chuỗi đó chiếm nhiều không gian hơn mức cần thiết trong cơ sở dữ liệu của bạn không làm phiền tôi. Điều làm phiền tôi là chạy vào những ngày như thế này:

11/10/2016

Và không biết đó là tháng thứ mười một hay tháng thứ mười.

Nhưng nó xác nhận bạn nói. Chắc chắn bạn đặt nó thông qua một quá trình xác nhận. Ngày hoàn toàn chính xác. Nhưng ở đây tôi đang duy trì điều này và tất cả những gì tôi biết là ngày là một chuỗi. Tôi thậm chí không thể nói cho bạn biết ngày này là ngày nào.

"Ngày thứ mười của tháng mười một trong năm hai mươi mười sáu của chúa chúng ta."

Đó là một chuỗi. Một trong những bài thuyết trình của chúng tôi cần nó ở định dạng đó. Bạn nói cơ sở dữ liệu chuyển đổi tất cả các ngày thành chuỗi phải không? Vui vẻ với điều đó.

Công việc của cơ sở dữ liệu là lưu trữ dữ liệu không hiện dữ liệu. Chắc chắn, bạn có thể làm điều đó trong chuỗi nhưng sau đó bạn phải phân tích nó để làm cho nó hữu ích để trình bày cho các định dạng khác. Lưu trữ nó ở dạng phân tích cú pháp tiêu chuẩn cho bất kỳ loại nào mà DB cung cấp giúp chúng tôi gần như sẵn sàng trình bày như chúng tôi có thể có mà không cần đưa ra quyết định thuyết trình. Nó thực sự không quan trọng với tôi nếu DB sao lưu kiểu đó bằng một chuỗi hoặc int hoặc byte. Miễn là nó biết nó đang làm gì.

Nhưng khi bạn không cho DB biết chúng tôi đang xử lý một ngày và lưu trữ một ngày dưới dạng một chuỗi bạn sẽ trình bày sớm và ưu tiên một bài thuyết trình hơn tất cả các bài thuyết trình khác. Điều này buộc tất cả những người thuyết trình khác phải phân tích cú pháp trước khi chuyển đổi. Không, cơ sở dữ liệu không phải là một phần của lớp trình bày. Đừng yêu cầu nó được.

Tương tự, lớp trình bày không phải là một phần của cơ sở dữ liệu, vì vậy sẽ không khôn ngoan khi kết hợp một báo cáo với các chi tiết cơ sở dữ liệu. Nó mạnh mẽ hơn nhiều để hành động trên các loại.


Câu trả lời này giải quyết lưu trữ dưới dạng chuỗi. Tuy nhiên, nó không giải quyết kiểu lưu trữ ngày phổ biến theo kiểu ngày gốc, nhưng sau đó định dạng chuỗi đó thành chuỗi trong truy vấn SQL , sử dụng các hàm như CONVERT (T-SQL), cũng không phải là DBMS thường tuần tự hóa ngày của nó thành một chuỗi trong một định dạng cấu hình bất cứ điều gì truy vấn. Ví dụ: postgresql.org/docs/9.5/static/ trên
dcorking

Đó là một báo cáo. Nó xảy ra sau khi lưu trữ. Giống như chuyển đổi ngày sinh của tôi thành tuổi của tôi.
candied_orange

2
Tôi chỉ muốn khuyến khích bạn mở rộng câu trả lời của mình, vì chủ đề của OP là cách " lấy ngày từ lớp cơ sở dữ liệu". Có một mẫu được thiết lập tốt, mặc dù được cho là không dùng nữa, trong đó một báo cáo truy vấn cơ sở dữ liệu cho các chuỗi ngày được định dạng và cục bộ. Tôi nghĩ rằng OP muốn nghe những lập luận phản đối đó. Tôi biết tôi sẽ làm.
dcorking

@dcorking cập nhật ghi chú.
candied_orange

+1 thêm nhiều nước hơn vào máy nghiền: chỉ cần tạo một hệ thống trên cơ sở được cài đặt kéo dài nhiều múi giờ trong đó tức thời tuyệt đối là tối quan trọng và xem bạn làm tốt như thế nào với chuỗi chuyển đổi dấu thời gian ở mọi nơi. Tệ nhất, hãy tạo một điểm mở rộng để mọi người tạo ra các plugin của riêng họ và cung cấp cho họ dấu thời gian khi các chuỗi xem các dấu thời gian này sẽ nhất quán như thế nào!
Newtopian

19

Địa phương

Chuyển đổi ngày thành chuỗi cho mục đích trình bày đòi hỏi phải biết sở thích của người dùng, vì cùng một ngày chính xác thường được hiển thị khác nhau cho người dùng ở các địa phương khác nhau. Ngay cả khi bạn sử dụng một miền địa phương trong ứng dụng của mình, hành vi thích hợp vẫn nên sử dụng miền địa phương của ứng dụng thay vì máy chủ cơ sở dữ liệu; và chúng không được đảm bảo giống hệt nhau ngay cả khi tại thời điểm này chúng trùng khớp ngẫu nhiên.

Việc chuyển đổi từ kiểu dữ liệu ngày phổ quát sang chuỗi cụ thể theo miền địa phương sẽ diễn ra trong lớp trình bày vì đó là lớp biết cách chuyển đổi đó nên được thực hiện.


3
Để có một ví dụ thực tế về sự không phù hợp của địa phương, hãy tưởng tượng viết một ứng dụng cho người dùng Maine, Hoa Kỳ và sau đó nó được lưu trữ trong trang trại máy chủ bờ tây của Amazon. ;) Đây thực sự không phải là một tình huống.
jpmc26

@ jpmc26 Tôi không hiểu sự khác biệt - Maine có sử dụng định dạng ngày khác với phần còn lại của Hoa Kỳ không?
Pete Kirkham

2
@PeteKirkham Maine và bờ biển phía tây Hoa Kỳ sử dụng các múi giờ cách nhau 3 giờ.
jpmc26

1
Hoặc một kịch bản thực tế khác: Hãy tưởng tượng việc điều hành một máy chủ ở Thụy Sĩ phải phục vụ khách hàng bằng bốn ngôn ngữ khác nhau (tiếng Đức, tiếng Pháp, tiếng Ý, tiếng Anh) với các ngôn ngữ khác nhau (và các quy tắc định dạng hơi khác nhau). Chúc may mắn chọn đúng miền cho máy chủ của bạn trong tình huống như vậy.
Voo

1
@ jpmc26 múi giờ và địa phương không giống nhau. Ví dụ: chúng tôi có văn phòng tại Glasgow Scotland, Atlanta USA và Pune Ấn Độ. Tư vấn trong các văn phòng này lần lượt theo dõi các trang web (cơ sở, bệnh viện, khách sạn, v.v.) trên khắp thế giới suốt ngày đêm. Cơ sở dữ liệu ứng dụng hoạt động trong UTC nhưng hiển thị thời gian theo giờ địa phương cho trang web được theo dõi. Các chuyên gia tư vấn Hoa Kỳ có ngày được bản địa hóa thành MM / DD / YYYY nhưng các địa phương của Vương quốc Anh và Ấn Độ là DD / MM / YYYY - điều này phụ thuộc vào ngôn ngữ, không phải múi giờ của trang web hoặc người dùng.
Pete Kirkham

9

Điều này là không mong muốn vì cùng một lý do bạn sẽ không muốn chuyển đổi một cách mù quáng bất kỳ loại nào thành một chuỗi ngay khi nó chạm vào tầng ứng dụng. Có nhiều khả năng bạn sẽ muốn sử dụng đối tượng đó theo một cách nào đó trước khi trình bày nó cho người dùng (nếu bạn thậm chí còn trình bày nó cho người dùng). Đối với ví dụ cụ thể này, hãy tưởng tượng bạn cần thực hiện một số phép toán ngày trên đối tượng. Không có nhược điểm nào khi chỉ chuyển đổi đối tượng thành một chuỗi chính xác trước khi bạn hiển thị nó.


4

Các loại tồn tại vì một lý do, nếu chúng không có lợi ích thì chúng ta sẽ không có chúng và sẽ không sử dụng chúng và chúng ta sẽ chỉ có "loại" và mọi thứ sẽ như vậy. Chúng không chỉ thuận tiện mà còn thêm an toàn và hiệu quả. Sau đây là danh sách lý do tại sao bạn phải luôn duy trì các loại ở định dạng gốc của chúng chứ không phải dưới dạng chuỗi . Tôi đã sử dụng DateTimenhư một ví dụ hầu hết thời gian nhưng các nguyên tắc tương tự áp dụng cho bất kỳ loại nguyên thủy nào như số nguyên, số thập phân, nhị phân, v.v.


Kho dữ liệu

Những ràng buộc

Loại ràng buộc

Hầu như tất cả các cửa hàng dữ liệu cho phép chỉ định các ràng buộc trên dữ liệu, điều này bao gồm các ràng buộc kiểu. Một trong những lợi ích chính của việc chỉ định một DateTimethể hiện là dữ liệu được lưu trữ sẽ bị ràng buộc với loại đó. Sẽ không bao giờ có thể nhập bất cứ thứ gì ngoài thời gian ngày bất kể dữ liệu được chèn vào cửa hàng như thế nào. Cái sau rất quan trọng đối với các hệ thống lớn hơn, nơi có nhiều quy trình tương tác trực tiếp với cửa hàng. Điều này cũng bao gồm cố gắng thêm các ngày bị lỗi như ngày 30 tháng 2, (của bất kỳ năm nào) vì tháng hai chỉ có thể có 29 ngày trong một năm nhuận và 28 ngày cho các năm không nhuận.

Các ràng buộc xác nhận

Ngoài ra còn có các ràng buộc xác thực có thể được triển khai trong Kho lưu trữ dữ liệu như đảm bảo rằng ngày được chèn không vượt quá ngày hiện tại hoặc ngày bắt đầu xảy ra trước ngày kết thúc.

Hoạt động

Hầu hết các cửa hàng dữ liệu cũng đã được xây dựng trong các hoạt động / chức năng như DateAddhoặc DateParttrong MS Sql Server. Điều này cho phép bạn bắt đầu lọc hoặc chọn dữ liệu cụ thể trong khi dữ liệu vẫn còn trong cửa hàng (chưa được truy xuất vào ứng dụng).

Định dạng được chấp nhận toàn cầu

Bằng cách sử dụng loại bản địa, các nhà phát triển hoặc hệ thống khác cũng tương tác với cửa hàng không cần phải được thông báo chi tiết về cách thức loại nguyên thủy đó được lưu trữ. Đây không phải là trường hợp nếu loại đó được lưu trữ dưới dạng một chuỗi, thì bạn phải đảm bảo rằng mọi người đều hiểu định dạng của DateTimebiểu diễn chuỗi đó . Hệ thống này trở nên mong manh khi xử lý dữ liệu bao gồm các vùng, vùng và văn hóa trong nguồn gốc dữ liệu, vị trí vật lý của ứng dụng và các thuộc tính của người dùng / hệ thống cuối đang tương tác với dữ liệu đó. Ví dụ: định dạng ngày ở một quốc gia có thể là MM / dd / yyyy (như ở Hoa Kỳ) nhưng ở một quốc gia khác có thể là dd / MM / yyyy, việc phát hiện sự khác biệt đó gần như không thể.

Tốc độ

Tốc độ truy xuất, tốc độ xác nhận, tốc độ hoạt động và hiệu quả lưu trữ là những yếu tố quan trọng. Ví dụ về tốc độ truy xuất: các kho lưu trữ dữ liệu cho phép các chỉ mục trên các cột và các chỉ mục này thường có thể được sử dụng hiệu quả hơn nếu loại được lưu trữ ở định dạng gốc.

Ứng dụng

Truy cập dữ liệu

Việc thực hiện các truy vấn đối với cửa hàng trở nên đơn giản hơn bằng cách sử dụng hệ thống kiểu gốc làm nhà phát triển, một lần nữa, không phải đoán định dạng lưu trữ. Hầu như tất cả các nhà cung cấp ứng dụng lưu trữ dữ liệu ( ví dụ: ado.net ) đều cung cấp các cơ chế để tạo các truy vấn được tham số hóa phù hợp dựa trên các kiểu gốc được truyền vào. Dưới đây là ví dụ về việc thêm phần Ngày vào truy vấn ado.net đối với cửa hàng Sql Server, làm tương tự với các chuỗi sẽ rất cồng kềnh và dễ bị lỗi / dễ bị lỗi.

command.Parameters.Add(new SqlParameter("@startDate", SqlDbType.Date) {Value = myDateInstance.Date});

Hoạt động

Các kiểu gốc trong mã cũng cung cấp cho các hoạt động tiêu chuẩn như loại .net System.Date. Các hoạt động thường có tính chất toán học như thêm ngày, tìm sự khác biệt giữa các ngày, v.v ... Một lần nữa, điều này không thể thực hiện dễ dàng trên các loại chuỗi.

Lớp trình bày

Địa phương

Khi một kiểu nguyên thủy cuối cùng được chuyển đổi thành một chuỗi trong lớp trình bày ( vị trí chính xác trong ngăn xếp chương trình để làm như vậy ), lập trình viên hiện có nhiều tùy chọn để hiển thị chính xác theo ngữ cảnh được trình bày. Bối cảnh này thường bao gồm ý nghĩa thực tế của dữ liệu và ngôn ngữ của người dùng.

ví dụ 1

Một thể hiện datetime có thể được định dạng tự động dựa trên miền địa phương của người dùng.

DateTime.Now.ToString("D", CultureInfo.GetCultureInfo(userContext.Culture))
Ví dụ 2

Một ví dụ thập phân có thể đại diện cho một số tiền (tiền tệ) và ngôn ngữ của người dùng sau đó cũng sẽ hiển thị số tiền theo sở thích của họ. Sau đó, một ứng dụng c # có thể hiển thị giá trị bằng cách sử dụng

amount.ToString("C", CultureInfo.GetCultureInfo(userContext.Culture))

Điều này có thể rất quan trọng vì các nền văn hóa khác nhau hiển thị số lượng khác nhau. Trong thời kỳ Hoa Kỳ (.) Và dấu phẩy (,) có nghĩa ngược chính xác như ở Hà Lan.

Vị trí

Điều này rất cụ thể cho các DateTimetrường hợp. Một ngày và thời gian biểu thị một sự xuất hiện tại một thời điểm cụ thể nhưng điều này thường phải được truyền đạt / trình bày cho người dùng tùy thuộc vào múi giờ của họ. Ví dụ: một DateTimethể hiện 2016-09-21T23:38:21.399Zcó thể được hiển thị như 9/21/2016 5:21 PMđối với người dùng ở múi giờ miền Đông Hoa Kỳ. Có nhiều cách để thực hiện điều này nhưng nó trở nên bất khả thi nếu trường hợp thời gian ngày được giữ trong bộ nhớ dưới dạng kiểu chuỗi hoặc trong kho lưu trữ dữ liệu dưới dạng kiểu chuỗi.


Nguyên tắc chung

2 quy tắc chung cho một ứng dụng tuân theo khi chuyển đổi bất kỳ kiểu nguyên thủy nào sang biểu diễn chuỗi là như sau

  • Khi chấp nhận đầu vào, chuyển đổi đầu vào đó thành kiểu nguyên thủy chính xác càng sớm càng tốt trong ngăn xếp chương trình (thường là trong lớp trình bày)
  • Khi truy xuất dữ liệu sẽ được hiển thị, chuyển đổi dữ liệu đó thành biểu diễn chuỗi càng muộn càng tốt trong ngăn xếp chương trình (một lần nữa, thường là trong lớp trình bày)

0

Thực sự không có gì sai khi làm điều này (nó được thực hiện mọi lúc trong các dịch vụ) miễn là bạn đang sử dụng một định dạng không mơ hồ cho ngày của bạn. Nói một cách rõ ràng, ý tôi không chỉ là ngày rõ ràng (ví dụ MM / DD so với DD / MM) mà còn cả múi giờ trong đó. Vì vậy, trước mắt, nếu bạn định biểu thị ngày của mình dưới dạng văn bản, hãy sử dụng định dạng ISO . Tôi rất thích chuỗi thời gian dựa trên UTC.

Ưu điểm:

  • Chuỗi ngày / giờ dựa trên tiêu chuẩn có thể mang theo và dễ hiểu
  • Thường ngày trong DB chứa một thành phần thời gian. Nếu điều này không có ý nghĩa với dữ liệu của bạn, điều này thực sự có thể đơn giản hóa mọi thứ.

Nhược điểm:

  • Kích thước dữ liệu. Định dạng bên trong của một ngày trong DB thường sẽ sử dụng ít không gian hơn so với kết xuất Chuỗi của ngày đó.
  • Bạn thường muốn đưa nó vào cấu trúc ngày hoặc thời gian thực trên máy khách để có thể có thêm thời gian để phân tích cú pháp.

Nếu ai đó nói rằng họ muốn làm điều này, tôi sẽ hỏi "tại sao?" bởi vì không có nhiều điểm cho nó Nếu lý do mà ai đó muốn trả lại ngày dưới dạng Chuỗi là vì họ sẽ chỉ hiển thị trực tiếp, thì đây không phải là lý do chính đáng để sử dụng Chuỗi từ DB.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.